装饰器(Decorators)是 Python 的一个重要部分。简单地说:**他们是修改其他函数的功能的函数。**他们有助于让我们的代码更简短。装饰器让你在一个函数的前后去执行代码。
1. 装饰器基础
1.1. 函数、对象和变量
由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。
def now():
print("2020-01-30")
f = now # 函数赋值给变量
f() # 通过变量调用函数
1.2. 一个简单的装饰器
装饰器就是一个返回函数的高阶函数
def log(func): # 接受函数作为参数
def wrapper(*args, **kwargs):
print("call %s" % func.__name__)
return func(*args, **kwargs)
return wrapper # 返回一个函数
@log
def now():
print("2020-01-30")
now()
out:
call now
2020-01-30
@log放在now函数上面,相当于执行了now = log(now)
1.3. 带参数的装饰器
如果装饰器需要传入参数,需要再封装一层。
def log(text):
def decorator(func):
def wrapper(*args, **kwargs):
print("%s, %s" % (text, func.__name__))
return func(*args, **kwargs)
return wrapper
return decorator
@log('execute') # 这里传入参数
def now():
print("2020-01-30")
now()
此时,相当于now = log(‘execute’)(now)
1.4. 解决函数签名变化的问题
上面不带参数和带参数的装饰器中,通过调用now.__name__发现返回值为wrapper,这是因为now=log(now),now=log(‘execute’)(now)的返回值是wrapper函数,因此,有些依赖函数签名的代码执行会发生错误。
functools.wraps可以解决这个问题。
import functools
def log(func): # 接受函数作为参数
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("call %s" % func.__name__)
return func(*args, **kwargs)
return wrapper # 返回一个函数
@log
def now():
print("2020-01-30")
now()
now.__name__
import functools
def log(text):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("%s, %s" % (text, func.__name__))
return func(*args, **kwargs)
return wrapper
return decorator
@log('execute')
def now():
print("2020-01-30")
now()
now.__name__
functools.wraps 旨在消除装饰器对原函数造成的影响,即对原函数的相关属性进行拷贝,已达到装饰器不修改原函数的目的。