【30天玩转python】装饰器与闭包

装饰器与闭包

装饰器和闭包是 Python 中非常强大的特性。理解它们不仅有助于写出更简洁和模块化的代码,还能极大地提高代码的复用性和灵活性。本节将详细介绍装饰器与闭包的概念、用法及其在实际编程中的应用。


1. 闭包

闭包(Closure)是指一个函数在其作用域之外调用时,依然能够访问其作用域内的变量。闭包函数可以捕获并保存外部函数中的局部变量,即使外部函数已经返回,这些变量依然能够被访问。

1.1 闭包的定义

要形成闭包,需要满足以下条件:

  1. 必须有一个嵌套函数(即函数内部定义了另一个函数)。
  2. 嵌套函数必须引用外部函数中的变量。
  3. 外部函数的返回值是嵌套函数。
1.2 示例
def outer_func(msg):
    def inner_func():
        print(msg)  # 引用了外部函数的变量
    return inner_func

closure = outer_func("Hello, Closure!")
closure()  # 输出:Hello, Closure!

在上面的例子中,inner_func() 是一个闭包,因为它访问了 outer_func() 的局部变量 msg,即使 outer_func() 已经返回。

1.3 闭包的应用

闭包可以用于保存状态或对某些参数进行预先配置。它经常用于工厂模式或装饰器中。

计数器闭包:

def make_counter():
    count = 0
    def counter():
        nonlocal count  # 声明count是外部函数的变量
        count += 1
        return count
    return counter

counter_a = make_counter()
print(counter_a())  # 输出:1
print(counter_a())  # 输出:2

counter_b = make_counter()
print(counter_b())  # 输出:1

2. 装饰器

装饰器(Decorator)是一个可以改变其他函数行为的函数。它允许在不修改原函数代码的情况下,向原函数添加新的功能。这使得代码更加灵活和可复用。

2.1 装饰器的定义

装饰器本质上是一个接受函数作为参数的函数,通常返回一个包装函数。这个包装函数会在原函数执行前或执行后添加额外的逻辑。

def decorator_func(func):
    def wrapper():
        print("在执行函数之前")
        func()  # 调用原函数
        print("在执行函数之后")
    return wrapper

@decorator_func  # 使用装饰器
def say_hello():
    print("Hello!")

say_hello()
# 输出:
# 在执行函数之前
# Hello!
# 在执行函数之后

在这个例子中,@decorator_func 是装饰器语法糖,它等价于 say_hello = decorator_func(say_hello)

2.2 带参数的装饰器

装饰器可以处理带有参数的函数。为了做到这一点,我们需要在包装函数中接受参数并传递给原函数。

def decorator_func(func):
    def wrapper(*args, **kwargs):  # 接受任意参数
        print("在执行函数之前")
        result = func(*args, **kwargs)
        print("在执行函数之后")
        return result
    return wrapper

@decorator_func
def add(a, b):
    return a + b

print(add(2, 3))  # 输出:在执行函数之前 5 在执行函数之后
2.3 带参数的装饰器(装饰器工厂)

如果需要让装饰器自身接受参数,我们需要使用一个多层嵌套的函数,即装饰器工厂。

def decorator_with_args(msg):
    def decorator_func(func):
        def wrapper(*args, **kwargs):
            print(f"Message: {msg}")
            return func(*args, **kwargs)
        return wrapper
    return decorator_func

@decorator_with_args("装饰器参数")
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")
# 输出:
# Message: 装饰器参数
# Hello, Alice!

3. 装饰器的实际应用

装饰器在实际编程中非常有用,尤其是在需要为多个函数添加相同的功能时。以下是一些常见的应用场景。

3.1 记录函数执行时间

通过装饰器来记录函数的执行时间,这在性能调优时非常有用。

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"{func.__name__} 执行时间: {end_time - start_time:.4f} 秒")
        return result
    return wrapper

@timer
def slow_function():
    time.sleep(2)

slow_function()
# 输出:slow_function 执行时间: 2.0001 秒
3.2 权限校验

装饰器可以用于实现权限校验,比如在某些 API 接口中,只允许授权用户访问。

def requires_permission(func):
    def wrapper(user):
        if user.get('is_admin'):
            return func(user)
        else:
            print("无权限访问")
    return wrapper

@requires_permission
def access_admin_panel(user):
    print("访问管理后台")

user = {"username": "alice", "is_admin": True}
access_admin_panel(user)  # 输出:访问管理后台

user = {"username": "bob", "is_admin": False}
access_admin_panel(user)  # 输出:无权限访问
3.3 缓存(Memoization)

装饰器可以用于缓存函数的计算结果,从而避免重复计算。这在处理递归函数时尤其有用,比如计算斐波那契数列。

def memoize(func):
    cache = {}
    def wrapper(n):
        if n not in cache:
            cache[n] = func(n)
        return cache[n]
    return wrapper

@memoize
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(10))  # 输出:55

4. 小结

  • 闭包:允许嵌套函数记住并访问外部函数的变量,哪怕外部函数已经返回。常用于保持状态或函数工厂。
  • 装饰器:是一种能够在不改变函数本身的情况下扩展其功能的工具,非常适合代码复用和功能增强。

装饰器与闭包都是 Python 中的高级功能,掌握它们不仅能使代码更具灵活性,还能减少重复代码,提高代码的可读性和维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱技术的小伙子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值