💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
推荐:「stormsha的主页」👈,「stormsha的知识库」👈持续学习,不断总结,共同进步,为了踏实,做好当下事儿~
非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨
💖The Start💖点点关注,收藏不迷路💖
|
📒文章目录
Python 装饰器使用详解
1. 装饰器基础概念
1.1 什么是装饰器?
装饰器本质是一个Python函数(或类),它可以在不修改原函数代码的情况下,动态地扩展函数或类的功能。其核心思想基于两点:
- 高阶函数:接收函数作为参数或返回函数的函数
- 闭包:嵌套函数能够访问外部作用域的变量
语法糖@decorator
使得装饰器调用更加简洁。例如:
@log_time
def calculate():
pass
等价于calculate = log_time(calculate)
1.2 为什么需要装饰器?
- DRY原则:避免重复代码(如多个函数都需要日志功能)
- 关注点分离:核心逻辑与辅助功能解耦
- 非侵入式扩展:不改动原函数代码即可添加新功能
1.3 装饰器的简单示例
def log_call(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with {args}")
return func(*args, **kwargs)
return wrapper
@log_call
def add(a, b):
return a + b
调用add(2, 3)
会输出日志信息并返回结果5
2. 装饰器的实现原理
2.1 高阶函数与闭包
def outer(msg):
def inner():
print(msg) # 访问外部作用域变量
return inner
closure = outer("Hello")
closure() # 输出 "Hello"
2.2 无参装饰器的实现
使用functools.wraps
保留原函数元信息:
from functools import wraps
def timer(func):
@wraps(func) # 保留__name__等属性
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(f"Time: {time.time()-start:.2f}s")
return result
return wrapper
2.3 带参数的装饰器
通过三层嵌套实现:
def repeat(n): # 外层接收参数
def decorator(func): # 中层接收函数
@wraps(func)
def wrapper(*args, **kwargs): # 内层实现逻辑
for _ in range(n):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def greet():
print("Hello")
调用greet()
会输出3次"Hello"
3. 装饰器的常见应用场景
3.1 日志记录
def log(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"[LOG] {func.__name__} called")
return func(*args, **kwargs)
return wrapper
3.2 性能测试
import time
def timeit(func):
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
print(f"{func.__name__} took {time.perf_counter()-start:.4f}s")
return result
return wrapper
3.3 权限校验
def check_login(func):
def wrapper(user, *args, **kwargs):
if not user.is_authenticated:
raise PermissionError("Login required")
return func(user, *args, **kwargs)
return wrapper
3.4 缓存与记忆化
from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
4. 类装饰器与高级用法
4.1 类作为装饰器
class CountCalls:
def __init__(self, func):
self.func = func
self.calls = 0
def __call__(self, *args, **kwargs):
self.calls += 1
print(f"Call {self.calls} of {self.func.__name__}")
return self.func(*args, **kwargs)
@CountCalls
def say_hello():
print("Hello")
4.2 多个装饰器的叠加
@log_call
@timeit
@check_login
def sensitive_operation(user):
pass
执行顺序:log_call(timeit(check_login(sensitive_operation)))
4.3 装饰器与设计模式
- 装饰器模式:动态添加职责
- AOP应用:通过装饰器实现横切关注点(如日志、事务)
5. 常见问题与最佳实践
5.1 调试技巧
- 使用
print(func.__name__)
检查函数名 inspect.signature(func)
查看参数签名
5.2 性能影响
- 每层装饰器增加一次函数调用开销
- 避免深层嵌套(如超过3层)
5.3 替代方案
- 上下文管理器:适合资源管理场景
with timeit_context():
do_something()
- 猴子补丁:运行时动态修改类/模块
6. 总结
- 装饰器本质是高阶函数+闭包的语法糖
- 典型应用:日志、性能测试、权限控制、缓存
- 进阶技巧:参数化装饰器、类装饰器、多装饰器组合
- 推荐实践:
- 始终使用
@wraps
保留元信息 - 避免过度装饰导致代码可读性下降
- 复杂逻辑考虑使用类装饰器
- 始终使用
通过实际项目练习,逐步掌握装饰器的灵活运用!
🔥🔥🔥道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙