@[toc]
Python的装饰器与元编程:代码的“魔法外衣”与“自动化工厂”
装饰器和元编程是Python最强大的元编程范式,它们能让你在不修改源代码的情况下增强函数/类的功能,或动态创建/修改代码结构。本文通过实战案例带你掌握这些“魔法工具”,提升代码的简洁性与复用性。
🔧 1. 函数装饰器:给函数穿上“功能外衣”
原理:装饰器本质是高阶函数——接收一个函数,返回一个新函数。其核心思想是函数嵌套 + 闭包,通过@语法糖实现功能增强。
实战1:计时器装饰器(性能分析)
import time
from functools import wraps
def timer(func):
@wraps(func) # 保留原函数元信息(如__name__)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs) # 执行原函数
end = time.perf_counter()
print(f"{func.__name__} 耗时: {end - start:.4f}秒")
return result
return wrapper
@timer
def data_processing(n):
"""模拟数据处理函数"""
time.sleep(n)
return "处理完成"
print(data_processing(2)) # 输出执行时间 + "处理完成"
关键点:
@wraps(func)解决装饰器导致的函数名、文档串丢失问题*args, **kwargs确保装饰器适配任意参数的函数
实战2:日志记录装饰器(调试神器)
def logger(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"[LOG] 调用 {func.__name__},参数: {args}, {kwargs}")
result = func(*args, **kwargs)
print(f"[LOG] {func.__name__} 返回: {result}")
return result
return wrapper
@logger
def add(a, b):
return a + b
add(3, b=5) # 输出调用和返回日志
🚀 2. 类装饰器与参数化装饰器
类装饰器原理:装饰器可以是一个类,通过实现__init__(接收函数)和__call__(执行包装逻辑)方法替代函数嵌套。
实战1:类装饰器实现单例模式
class Singleton:
def __init__(self, cls):
self.cls = cls
self.instance = None
def __call__(self, *args, **kwargs):
if self.instance is None:
self.instance = self.cls(*args, **kwargs)
return self.instance
@Singleton
class Database:
def __init__(self, name):
self.name = name
db1 = Database("MySQL")
db2 = Database("PostgreSQL")
print(db1 is db2) # 输出 True(始终返回同一实例)
参数化装饰器原理:通过三层嵌套函数实现:外层接收装饰器参数 → 中层接收被装饰函数 → 内层执行包装逻辑。
实战2:带参数的API限流装饰器
def rate_limiter(max_calls, period):
"""限制 period 秒内最多调用 max_calls 次"""
def decorator(func):
calls = []
@wraps(func)
def wrapper(*args, **kwargs):
now = time.time()
# 移除超时记录
calls[:] = [t for t in calls if now - t < period]
if len(calls) >= max_calls:
raise Exception("API调用频率超限!")
calls.append(now)
return func(*args, **kwargs)
return wrapper
return decorator
@rate_limiter(max_calls=3, period=10) # 10秒内最多调用3次
def fetch_data():
return "数据获取成功"
for _ in range(4): # 第4次触发异常
print(fetch_data())
⚙️ 3. 元编程实战:用元类自动注册类
元类原理:元类是创建类的类(如type)。自定义元类需继承type,重写__new__或__init__,在类创建时修改其属性。
实战:自动注册所有子类(插件系统基础)
class PluginMeta(type):
registry = {}
def __init__(cls, name, bases, attrs):
super().__init__(name, bases, attrs)
if name != "BasePlugin": # 跳过基类
PluginMeta.registry[name] = cls
class BasePlugin(metaclass=PluginMeta):
pass
class EmailPlugin(BasePlugin):
def run(self):
print("发送邮件")
class SMSPlugin(BasePlugin):
def run(self):
print("发送短信")
print(PluginMeta.registry) # 输出: {'EmailPlugin': <class ...>, 'SMSPlugin': ...}
💎 装饰器 vs 元类:如何选择?
| 特性 | 装饰器 | 元类 |
|---|---|---|
| 作用对象 | 函数/类(增强功能) | 类(控制创建过程) |
| 复杂度 | 低 → 中(参数化时) | 高 |
| 适用场景 | 功能增强(日志、缓存等) | 框架级控制(ORM、插件系统) |
| 侵入性 | 非侵入(通过@添加) | 需继承(metaclass=...) |
最佳实践:
- 优先用装饰器解决功能扩展问题
- 元类适用于需要统一修改多个类的场景(如API框架)
下期预告:16.Python并发编程模型:突破性能瓶颈的利器 核心内容:
- ✨ 多线程 vs 多进程:GIL锁的真相与规避策略
- ⚡ 协程与异步IO:
asyncio实现高并发Web爬虫 - 🔥 实战案例:
- 使用线程池加速I/O密集型任务
- 利用多进程突破CPU计算瓶颈
- 分布式任务队列(Celery)架构设计
思考题:多线程处理HTTP请求时,为什么有时比单线程更慢?答案下期揭晓!
掌握装饰器与元编程,你已拥有“代码自动化生产”的钥匙。它们如同编程世界的魔法,让复杂需求变得优雅简洁 ✨。
更多技术干货欢迎关注微信公众号“科威舟的AI笔记”~
【转载须知】:转载请注明原文出处及作者信息