python的装饰器和闭包
python的装饰器和闭包
内容
Python 的装饰器是什么?
装饰器(Decorator)是 Python 中的一种用于扩展或修改函数/类行为的设计模式。它允许在不修改原有函数或类的情况下,动态地为其增加新的功能。这种功能在实践中非常有用,例如在日志记录、性能测试、权限控制、缓存等场景中。
装饰器的定义与使用
- 装饰器的基本结构是一个函数,它接收另一个函数作为参数,并返回一个新的函数。
- 使用装饰器时,通常通过
@decorator_name
的语法,将其作用于某个函数或方法。
简单示例:
def my_decorator(func):
def wrapper():
print("调用函数前的操作")
func()
print("调用函数后的操作")
return wrapper
@my_decorator # 等同于 say_hello = my_decorator(say_hello)
def say_hello():
print("Hello, World!")
say_hello()
输出:
调用函数前的操作
Hello, World!
调用函数后的操作
解释:
@my_decorator
装饰器将say_hello()
函数传递给my_decorator()
。my_decorator
返回一个新的函数wrapper
,该函数包装了原始的say_hello()
。- 当调用
say_hello()
时,实际执行的是wrapper()
,从而在调用原函数前后添加了新的行为。
带参数的装饰器:
如果被装饰的函数接受参数,那么 wrapper
函数也需要接受相应的参数:
def my_decorator(func):
def wrapper(*args, **kwargs):
print("调用函数前的操作")
result = func(*args, **kwargs)
print("调用函数后的操作")
return result
return wrapper
@my_decorator
def add(a, b):
print(f"计算 {a} + {b}")
return a + b
result = add(3, 5)
print(f"结果是: {result}")
输出:
调用函数前的操作
计算 3 + 5
调用函数后的操作
结果是: 8
解释:
- 使用
*args
和**kwargs
,确保装饰器可以支持任意参数的函数。
多个装饰器的使用:
多个装饰器可以层层叠加,执行顺序是从上到下应用装饰器:
def decorator1(func):
def wrapper():
print("执行 decorator1")
func()
return wrapper
def decorator2(func):
def wrapper():
print("执行 decorator2")
func()
return wrapper
@decorator1
@decorator2
def say_hi():
print("Hi!")
say_hi()
输出:
执行 decorator1
执行 decorator2
Hi!
解释:
@decorator1
包裹了@decorator2
,所以decorator1
先执行。
装饰器的实际应用场景:
- 日志记录:
def log(func):
def wrapper(*args, **kwargs):
print(f"正在调用 {func.__name__} 函数")
return func(*args, **kwargs)
return wrapper
@log
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
输出:
正在调用 greet 函数
Hello, Alice!
- 权限控制:
def require_permission(permission):
def decorator(func):
def wrapper(*args, **kwargs):
if permission != "admin":
print("权限不足,无法执行该操作")
return
return func(*args, **kwargs)
return wrapper
return decorator
@require_permission("user")
def delete_user():
print("用户已删除")
delete_user()
输出:
权限不足,无法执行该操作
类装饰器:
除了装饰函数之外,装饰器还可以用于装饰类:
def add_method(cls):
cls.new_method = lambda self: print("这是新添加的方法")
return cls
@add_method
class MyClass:
pass
obj = MyClass()
obj.new_method() # 调用装饰器添加的新方法
输出:
这是新添加的方法
总结:
- 装饰器是一种强大的工具,可以动态地为函数或类添加功能。
- 它们通过
@decorator
的语法,使代码更加简洁和易读。 - 常见的应用场景包括:日志记录、权限控制、缓存、性能监控等。
理解装饰器的关键在于:装饰器本质上是高阶函数,它们接收一个函数或类并返回一个新的函数或类。装饰器的使用可以大大提高代码的复用性和可维护性。
什么是闭包?
闭包(Closure)是指在内嵌函数中,引用了外部函数中的变量,并且即使外部函数执行完毕,这些变量仍然保存在内嵌函数的作用域中。这种结构使得函数能够“记住”其外部环境的变量。
闭包的核心在于:
- 函数嵌套:函数内部定义另一个函数。
- 外层函数的变量被内层函数引用。
- 外层函数的作用域结束后,变量依然保存在内层函数中。
闭包的简单例子
def outer_function(x):
def inner_function(y):
return x + y # 内嵌函数引用了外部函数的变量 x
return inner_function # 返回内嵌函数
closure = outer_function(10) # outer_function 执行完毕,返回 inner_function
result = closure(5) # 相当于调用 inner_function(5)
print(result) # 输出: 15
解释:
outer_function
接受一个参数x
,并定义了一个内嵌函数inner_function
。inner_function
使用了外部函数outer_function
中的变量x
。- 当
outer_function
执行完毕后,返回inner_function
函数对象。 - 虽然
outer_function
的作用域已经结束,但由于inner_function
是闭包,它保留了对变量x
的引用。
闭包的作用
- 保存状态:闭包可以记住函数的某些状态,即使外部作用域已经结束。
- 延迟执行:闭包可以延迟计算或操作,直到真正需要时才执行。
- 函数式编程的基础:在某些语言中(如 Python、JavaScript),闭包是实现回调、装饰器等模式的重要基础。
闭包与作用域的关系
让我们再看一个涉及作用域的闭包示例:
def counter():
count = 0 # 外部变量
def increment():
nonlocal count # 使用 nonlocal 声明引用外层作用域中的变量
count += 1
return count
return increment
counter_fn = counter() # 返回内嵌的 increment 函数
print(counter_fn()) # 输出: 1
print(counter_fn()) # 输出: 2
print(counter_fn()) # 输出: 3
解释:
counter
函数创建了一个变量count
,并返回一个increment
内嵌函数。- 每次调用
increment
时,都会更新并返回count
的值。 - 由于
increment
是闭包,它可以访问外部函数的变量count
,即使counter
已经执行完毕。
闭包的常见应用:
1. 装饰器:
装饰器本质上就是闭包,封装了原函数及其状态。
def multiply_by(factor):
def decorator(func):
def wrapper(*args, **kwargs):
return factor * func(*args, **kwargs)
return wrapper
return decorator
@multiply_by(2)
def add(a, b):
return a + b
print(add(3, 5)) # 输出: 16
解释:
- 装饰器
multiply_by(2)
创建了一个闭包,将factor=2
存在wrapper
中。 - 当调用
add(3, 5)
时,装饰器将结果乘以2
。
2. 回调函数:
闭包常用于异步编程中的回调函数,保存状态直到异步操作完成。
总结:
闭包(Closure)是函数的一种特性,使得内嵌函数可以“记住”外部函数的变量,即使外部函数已经执行完毕。这种特性使得闭包在编程中非常有用,尤其是在处理状态保存、装饰器和回调函数时。
关键点:
- 内嵌函数引用外部函数中的变量。
- 外部函数执行完毕后,内嵌函数仍然可以使用这些变量。
nonlocal
关键字允许内嵌函数修改外部作用域中的变量。
闭包不仅使代码更加简洁,还能实现强大的功能,是 Python 编程中的重要概念。