模块课程(4/4)
装饰器:修饰函数的函数
装饰器是一个函数,它接受另一个函数并返回一个 它的“装饰”版本。这是添加行为的有效方法 (日志记录、计时、缓存、重试、验证),无需触及主体 原来的函数。
函数作为值
在 Python 中,函数是对象:您可以传递它们、返回它们、分配它们。
def saluta():
print("ciao")
f = saluta # NIENTE parentesi: assegno la funzione
f() # 'ciao'一个最小的装饰器
def log(func):
def wrapper(*args, **kwargs):
print(f"chiamo {func.__name__}")
risultato = func(*args, **kwargs)
print(f"ho finito {func.__name__}")
return risultato
return wrapper
def somma(a, b):
return a + b
somma = log(somma) # ora somma è "wrapper"
somma(2, 3)
# chiamo somma
# ho finito somma
# 5@decorator 语法
使用 @ 可以更优雅地编写赋值 somma = log(somma):
@log
def somma(a, b):
return a + b这是完全相同的事情。上面的 @log 定义相当于:
“一旦定义了此函数,请将其替换为 log(function)”。
*args, **kwargs:接受任何签名
def wrapper(*args, **kwargs):
return func(*args, **kwargs)*args 收集位置参数,**kwargs 关键字参数。他们让
您编写适用于任何函数的包装器。
functools.wraps:保留元数据
如果没有wraps,修饰函数就会失去__name__、__doc__,提示:
from functools import wraps
def log(func):
@wraps(func)
def wrapper(*args, **kwargs):
...
return func(*args, **kwargs)
return wrapper示例:@timeit
from functools import wraps
import time
def timeit(func):
@wraps(func)
def wrapper(*args, **kwargs):
t0 = time.perf_counter()
risultato = func(*args, **kwargs)
dt = time.perf_counter() - t0
print(f"{func.__name__} ha impiegato {dt*1000:.2f} ms")
return risultato
return wrapper
@timeit
def somma_grande():
return sum(range(10**6))
somma_grande()来自 stdlib 的装饰器
from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
if n < 2: return n
return fib(n - 1) + fib(n - 2)
fib(100) # istantaneo grazie alla cache@lru_cache— 记住纯函数的结果。@property— 将方法公开为属性(在 OOP 模块中看到)。@staticmethod、@classmethod— 更改self的传递方式。
带参数的装饰器
装饰器也可以接受参数。要实现此目的,必须编写三层嵌套函数:最外层函数接收装饰器的参数,中间函数接收装饰函数,最内层函数 (wrapper) 接收调用期间传递给装饰函数的实际参数。
自己尝试一下
编写一个装饰器“double_result”,调用装饰函数并返回其结果 * 2. 将其应用于返回 x + 1 的函数“f(x)”。评估“f(10)”。
显示提示
包装器调用 func 并返回乘以 2 的结果。
3 次尝试后可用的解决方案
复习练习
使用 functools.lru_cache 加速递归 fib(n) 函数。计算 fib(30) 并分配给“r”。评估“r”。
显示提示
@lru_cache(maxsize=None) 高于 def。
3 次尝试后可用的解决方案
额外的挑战
Define a decorator `double_result` that doubles (multiplies by 2) the return value of the decorated function. Apply the decorator to the function `def sum_nums(a, b): return a + b`. Finally, evaluate `sum_nums(3, 4)`.
显示提示
包装器调用 func(*args, **kwargs) 并将结果乘以 2。
3 次尝试后可用的解决方案