Python 闭包及装饰器
闭包是指延伸了作用域的函数。
自由变量(free variable) 指未在本地作用域中绑定的变量
函数装饰器用于在源码中标记函数, 以某种方式增强函数的行为。
装饰器实质,把被装饰的函数替换为新函数, 二者接收相同的参数,绑定了被装饰函数最为自由变量,返回被装饰函数本该返回的值,同时还会做些额外操作
装饰器的一个特性就是他们在被装饰的函数定义之后立即执行
实现一个简单的装饰器:
def decorate(func):
def inner(*args, **kwargs):
print("我是装饰器")
func(*args, **kwargs)
return inner
@decorate # 相当于 func = decorator(func(*args, **kwargs)) = inner(*args, **kwargs) 同时绑定了被装饰函数的引用作为自由变量
def func(*args, **kwargs):
pass
@decorate
class Test(*args, **kwargs): # 相当于 Test = decorate(Test(*args, **kwargs)) = inner(*args, **kwargs) 同时绑定了被装饰函数的引用作为自由变量
pass
print(func.__code__.co_freevars) # 查看自由变量
print(func.__code__.co_varnames) # 查看局部变量
叠加装饰器:
def decorate1(func): def inner1(*args, **kwargs): print("装饰器1开始装饰") func(*args, **kwargs) print("装饰器1装饰结束") return inner1 def decorate2(func): def inner2(*args, **kwargs): print("装饰器2开始装饰") func(*args, **kwargs) print("装饰器2装饰结束") return inner2 @decorate1 # 相当于 func = decorate1(decorate2(func(*args, **kwargs))) = inner1(inner2)同时绑定了被装饰函数的引用作为自由变量 @decorate2 def func(*args, **kwargs): pass
参数化装饰器:
创建一个装饰器工厂函数,将参数传给它,返回一个装饰器, 再应用到被装饰的函数上
def register(active=True):
def decorate(func):
def inner(*args, **kwargs):
print('before')
func(*args, **kwargs)
if active:
print('another operation')
print('after')
return inner
return decorate
@register(True) # 相当于 func = decorate(func(*args, **kwargs)) = inner(*args, **args) 同时绑定了参数active以及被装饰函数的引用作为自由变量
def func(a=1):
print(a)
print(func.__code__.co_freevars)
类实现装饰器
class Decorator: def __init__(self, func): self._func = func def __call__(self, *args, **kwargs): print('__call__') self._func(*args, **kwargs) @Decorator def func(*args, **kwargs): # func = Decorator(func(*args, **kwargs)) = obj 同时绑定了被装饰函数的引用作为实例 pass func()
参数化类装饰器 : 类作为装饰器工厂, 实例为装饰器, 参数保存再实例中,将实例作为装饰器应用到被装饰函数上
class Decorator: def __init__(self, active): self._active = active def __call__(self, func): def wrapper(*args, **kwargs): if self._active: print("another operation") func(*args, **kwargs) return wrapper @Decorator(active=True) def func(*args, **kwargs): # func = obj(func(*args, **kwargs)) = wrapper(*args, **kwargs) 同时绑定了参数active作为实例 pass func()