Contents
30.3.8. functools.wraps定义函数修饰器¶
Python中有一种特殊的写法,可以用修饰器(decorator)来封装某个函数,从而让程序在执行这个函数之前与执行完这个函数之后,分别运行某些代码。
这意味着,调用者传给函数的参数值、函数返回给调用者的值,以及函数抛出的异常,都可以由修饰器访问并修改。
这是个很有用的机制,能够确保用户以正确的方式使用函数,也能够用来调试程序或实现函数注册功能,此外还有许多用途。
from functools import wraps
import pickle
def trace(func):
# @wraps(func)
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
print(f"{func.__name__}({args},{kwargs})"
f"-> {result}")
return result
return wrapper
@trace
def fibonacci(n):
"""
Args:
n:
Returns: the n-th Fibonacci number
"""
if n in (0, 1):
return n
return (fibonacci(n - 2) + fibonacci(n - 1))
fibonacci(4)
print(fibonacci)
print(pickle.dumps(fibonacci))
"""
Traceback (most recent call last):
AttributeError: Can't pickle local object 'trace.<locals>.wrapper'
<function trace.<locals>.wrapper at 0x0000024EF5613BF8>
"""
这种现象解释起来并不困难。trace函数返回的,是它里面定义的wrapper函数,所以,当我们把这个返回值赋给fibonacci之后,fibonacci这个名称所表示的自然就是wrapper了。
from functools import wraps
import pickle
def trace(func):
@wraps(func)
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
print(f"{func.__name__}({args},{kwargs})"
f"-> {result}")
return result
return wrapper
@trace
def fibonacci(n):
"""
Args:
n:
Returns: the n-th Fibonacci number
"""
if n in (0, 1):
return n
return (fibonacci(n - 2) + fibonacci(n - 1))
fibonacci(4)
print(fibonacci)
print(pickle.dumps(fibonacci))
"""
<function trace.<locals>.wrapper at 0x0000024EF5613BF8>
b'\x80\x03c__main__\nfibonacci\nq\x00.'
"""
对象序列化器,现在也正常了。
除了这里讲到的几个方面之外,Python函数还有很多标准属性(例如___name__、__module__、__annotations__)也应该在受到封装时得以保留,这样才能让相关的接口正常运作。wraps可以帮助保留这些属性,使程序表现出正确的行为。
要点:
修饰器是Python中的一种写法,能够把一个函数封装在另一个函数里面,这样程序在执行原函数之前与执行完毕之后,就有机会执行其他一些逻辑了。
修饰器可能会让那些利用introspection机制运作的工具(例如调试器)产生奇怪的行为。
Python内置的functools模块里有个叫作wraps的修饰器,可以帮助我们正确定义自己的修饰器,从而避开相关的问题。