装饰器本质上是一个接受函数作为参数并返回新函数的高阶函数:
def my_decorator(func):
def wrapper():
print("函数执行前")
func()
print("函数执行后")
return wrapper
# 下面的代码
def say_hello():
print("Hello!")
say_hello = my_decorator(say_hello)
# 等效于
@my_decorator
def say_hello():
print("Hello!")
say_hello()
# 输出:
# 函数执行前
# Hello!
# 函数执行后
多个装饰器叠加
可以同时使用多个装饰器,执行顺序为从下到上:
@decorator_a
@decorator_b
def func():
pass
# 等效于:
# func = decorator_a(decorator_b(func))
实现timer装饰器
def timer(func):
import time
def wrapper():
start = time.time()
func()
end = time.time()
cost = end - start
print(f"{func.__name__} 执行时间: {cost:.4f} 秒")
return wrapper
@timer
def slow_function():
time.sleep(1)
return "Done"
slow_function()
实现wraps装饰器
实现wraps装饰器,用于不改变函数的名称和注释
def wraps(func):
def decorator(wrapper):
wrapper.__name__ = func.__name__
wrapper.__doc__ = func.__doc__
return wrapper
return decorator
def my_decorator(func):
@wraps(func)
def wrapper():
print("函数执行前")
func()
print("函数执行后")
return wrapper
@my_decorator
def say_hello():
"""打招呼"""
print("Hello!")
say_hello()
# 输出:
# 函数执行前
# Hello!
# 函数执行后
print("name", say_hello.__name__)
print("doc", say_hello.__doc__)
# 输出:
# name say_hello
# doc 打招呼
实现repeat装饰器
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
t = n
while t > 0:
func(*args, **kwargs)
t -= 1
return wrapper
return decorator
@repeat(3)
def say_hello(s):
print(s)
say_hello(1) # 输出: 1 1 1
实现cache装饰器
编写一个装饰器 cache,缓存函数的计算结果。当使用相同的参数调用函数时,直接返回缓存的结果:
def cache(func):
_cache = {}
def wrapper(*args, **kwargs):
key = (args, tuple(kwargs.items()))
if key not in _cache:
_cache[key] = func(*args, **kwargs)
return _cache[key]
return wrapper
@cache
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(60)) # 应该快速返回结果,输出: 9227465
提示: 使用字典存储参数到结果的映射。
实现to_dict装饰器
编写一个类装饰器 to_dict,自动为类生成 to_dict 方法,该方法可以将对象转换为字典
def to_dict(cls):
def to_dict_method(self):
return self.__dict__
cls.to_dict = to_dict_method
return cls
@to_dict
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(3, 4)
print(p.to_dict()) # 输出: {'x': 3, 'y': 4}




