前言
装饰器(Decorator)和元类(Metaclass)是 Python 最强大的两个”语法糖”。装饰器让我们在不修改原函数/类的前提下,动态地增强其行为;元类则让我们在类创建时介入,控制整个类的生成过程。
它们是 Python 中面向切面编程和黑魔法的代表——用得恰当可以让代码优雅简洁,用得过度则会让代码难以理解。
本文将系统讲解:
- 装饰器:从闭包到函数装饰器,再到类装饰器
- 元类:类的创建过程与元类的介入机制
- 实战场景:缓存、日志、性能分析、注册模式等
- 最佳实践:何时用装饰器,何时用元类
函数基础:闭包
什么是闭包
# 闭包 = 函数 + 外部作用域的变量引用
def outer(x):
def inner(y):
return x + y # 引用外部变量 x
return inner
closure = outer(10)
print(closure(5)) # 15
print(closure(3)) # 13
# inner 函数"记住"了 x=10,即使 outer 已经返回
闭包的经典应用:计数器
def make_counter():
count = 0 # 外部变量
def counter():
nonlocal count # 声明使用外部变量
count += 1
return count
return counter
counter1 = make_counter()
counter2 = make_counter()
print(counter1()) # 1
print(counter1()) # 2
print(counter2()) # 1(独立的作用域)
print(counter1()) # 3
闭包 vs 普通函数
| 特性 | 普通函数 | 闭包 |
|---|---|---|
| 状态保持 | 无状态 | 可保持外部状态 |
| 内存 | 函数结束时释放 | 引用存在则不释放 |
| 用途 | 一次性计算 | 工厂函数、回调 |
| 性能 | 轻量 | 略重,但功能强大 |
装饰器基础
装饰器是什么
# 装饰器本质:高阶函数,接受函数作为参数,返回增强后的函数
# 原始函数
def original_function():
return "原始功能"
# 装饰器
def my_decorator(func):
def wrapper(*args, **kwargs):
print("调用前增强")
result = func(*args, **kwargs)
print("调用后增强")
return result
return wrapper
# 使用 @ 语法糖
@my_decorator
def original_function():
return "原始功能"
# 等价于
# original_function = my_decorator(original_function)
# 调用
result = original_function()
# 输出:
# 调用前增强
# 调用后增强
# result = "原始功能"
无参数函数的装饰器
import time
def timer(func):
"""计时装饰器"""
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
elapsed = time.time() - start
print(f"{func.__name__} 执行耗时: {elapsed:.4f}s")
return result
return wrapper
@timer
def slow_function():
time.sleep(1)
return "完成"
@timer
def fast_function():
return "完成"
slow_function()
# 输出: slow_function 执行耗时: 1.0032s
fast_function()
# 输出: fast_function 执行耗时: 0.0001s
*args 和 **kwargs 的作用
def debug(func):
"""调试装饰器:打印函数调用信息"""
def wrapper(*args, **kwargs):
print(f"调用 {func.__name__}")
print(f" 位置参数: {args}")
print(f" 关键字参数: {kwargs}")
result = func(*args, **kwargs)
print(f" 返回值: {result}")
return result
return wrapper
@debug
def add(a, b):
return a + b
@debug
def greet(name, prefix="Hello"):
return f"{prefix}, {name}!"
add(1, 2)
# 输出:
# 调用 add
# 位置参数: (1, 2)
# 关键字参数: {}
# 返回值: 3
greet("Alice", prefix="Hi")
# 输出:
# 调用 greet
# 位置参数: ('Alice',)
# 关键字参数: {'prefix': 'Hi'}
# 返回值: Hi, Alice!
带参数的装饰器
双层嵌套:装饰器工厂
# 单参数装饰器
def repeat(times):
"""重复执行函数指定次数"""
def decorator(func):
def wrapper(*args, **kwargs):
results = []
for _ in range(times):
results.append(func(*args, **kwargs))
return results
return wrapper
return decorator
@repeat(3)
def say_hello():
return "Hello!"
print(say_hello()) # ['Hello!', 'Hello!', 'Hello!']
@repeat(2)
def add(a, b):
return a + b
print(add(1, 2)) # [3, 3]
多参数装饰器工厂
def repeat(times=None, delay=0):
"""重复执行,可选延迟"""
def decorator(func):
def wrapper(*args, **kwargs):
import time
results = []
for i in range(times or 1):
result = func(*args, **kwargs)
results.append(result)
if i < times - 1 and delay:
time.sleep(delay)
return results
return wrapper
return decorator
@repeat(times=3, delay=1)
def fetch_data():
return "数据"
# 执行 fetch_data 将重复3次,每次间隔1秒
装饰器带参数的三种写法
# 写法1:@repeat(3) — 推荐
@repeat(3)
def func1():
pass
# 写法2:@repeat() — 无参数
@repeat()
def func2():
pass
# 写法3:@repeat — 不带括号(需要装饰器支持)
# 注意:这要求装饰器本身可调用
def simple_decorator(func):
# ...
@simple_decorator # 等价于 @simple_decorator
def func3():
pass
装饰器组合
def deco1(func):
def wrapper(*args, **kwargs):
print("装饰器1开始")
result = func(*args, **kwargs)
print("装饰器1结束")
return result
return wrapper
def deco2(func):
def wrapper(*args, **kwargs):
print("装饰器2开始")
result = func(*args, **kwargs)
print("装饰器2结束")
return result
return wrapper
# 装饰器从下往上应用
@deco1
@deco2
def my_func():
print("执行函数")
my_func()
# 输出顺序:
# 装饰器1开始
# 装饰器2开始
# 执行函数
# 装饰器2结束
# 装饰器1结束
类装饰器
类装饰器基础
# 类装饰器:接受类作为参数,返回类(或修改类)
def add_method(cls):
"""为类添加方法"""
def new_method(self):
return "新增方法"
cls.new_method = new_method
return cls
@add_method
class MyClass:
def original(self):
return "原有方法"
obj = MyClass()
print(obj.original()) # "原有方法"
print(obj.new_method()) # "新增方法"
常用类装饰器模式
# 模式1:注册器(Registry)
class_registry = {}
def register(cls):
"""注册类到全局注册表"""
class_registry[cls.__name__] = cls
return cls
@register
class User:
pass
@register
class Product:
pass
print(class_registry) # {'User': <class '__main__.User'>, 'Product': <class '__main__.Product'>}
# 模式2:添加类方法
def class_method(*method_names):
"""批量添加类方法"""
def decorator(cls):
for name in method_names:
setattr(cls, name, classmethod(lambda cls: f"类方法: {name}"))
return cls
return decorator
@class_method("create", "destroy")
class Service:
pass
print(Service.create()) # "类方法: create"
print(Service.destroy()) # "类方法: destroy"
# 模式3:实例计数
def count_instances(cls):
"""统计类实例数量"""
cls._count = 0
original_init = cls.__init__
def new_init(self, *args, **kwargs):
cls._count += 1
original_init(self, *args, **kwargs)
cls.__init__ = new_init
return cls
@count_instances
class Tracked:
pass
a = Tracked()
b = Tracked()
c = Tracked()
print(Tracked._count) # 3
类方法 vs 静态方法装饰器
class MyClass:
def instance_method(self):
"""实例方法:需要 self"""
return "实例方法"
@classmethod
def class_method(cls):
"""类方法:需要 cls"""
return f"类方法 via {cls.__name__}"
@staticmethod
def static_method():
"""静态方法:不需要 self 或 cls"""
return "静态方法"
obj = MyClass()
print(obj.instance_method()) # "实例方法"
print(MyClass.class_method()) # "类方法 via MyClass"
print(MyClass.static_method()) # "静态方法"
print(obj.static_method()) # "静态方法"(也可用实例调用)
# 在装饰器中保留这些特性
def add_class_methods(methods_dict):
"""动态添加类方法和静态方法"""
def decorator(cls):
for name, method in methods_dict.items():
if isinstance(method, staticmethod):
setattr(cls, name, method.__func__)
elif isinstance(method, classmethod):
setattr(cls, name, method.__func__)
else:
setattr(cls, name, staticmethod(method))
return cls
return decorator
functools 工具箱
@functools.wraps — 保留元信息
import functools
def my_decorator(func):
@functools.wraps(func) # 关键!保留原函数信息
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@my_decorator
def documented_function():
"""这是一个有文档字符串的函数"""
pass
print(documented_function.__name__) # "documented_function"(而非 "wrapper")
print(documented_function.__doc__) # "这是一个有文档字符串的函数"
print(documented_function.__module__) # "__main__"
# 不使用 @wraps 的问题
def bad_decorator(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@bad_decorator
def another_function():
"""文档"""
pass
print(another_function.__name__) # "wrapper" ← 丢失!
print(another_function.__doc__) # None ← 丢失!
functools.lru_cache — 缓存结果
import functools
import time
@functools.lru_cache(maxsize=128)
def fibonacci(n):
"""斐波那契数列(带缓存)"""
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
# 性能对比
def fibonacci_slow(n):
"""不使用缓存"""
if n < 2:
return n
return fibonacci_slow(n-1) + fibonacci_slow(n-2)
# 测试
start = time.time()
result = fibonacci_slow(35)
print(f"无缓存: {time.time() - start:.4f}s") # ~1.5s
start = time.time()
result = fibonacci(35)
print(f"有缓存: {time.time() - start:.4f}s") # ~0.0001s
# 查看缓存状态
print(fibonacci.cache_info())
# CacheInfo(hits=33, misses=36, maxsize=128, currsize=36)
functools.partial — 偏函数
import functools
def power(base, exponent):
return base ** exponent
# 创建偏函数:固定 exponent=2
square = functools.partial(power, exponent=2)
print(square(5)) # 25
print(square(10)) # 100
# 创建偏函数:固定 base=2
cube = functools.partial(power, 2) # 位置参数
print(cube(3)) # 8
print(cube(4)) # 16
# 实际应用:日志记录器
def log(level, message):
print(f"[{level}] {message}")
debug_log = functools.partial(log, "DEBUG")
info_log = functools.partial(log, "INFO")
debug_log("调试信息") # [DEBUG] 调试信息
info_log("普通信息") # [INFO] 普通信息
functools.singledispatch — 泛型函数
import functools
@functools.singledispatch
def serialize(obj):
"""默认序列化"""
return str(obj)
@serialize.register(int)
def _(n):
return f"整数: {n}"
@serialize.register(str)
def _(s):
return f"字符串: {s}"
@serialize.register(list)
def _(lst):
return f"列表: {', '.join(str(x) for x in lst)}"
print(serialize(42)) # "整数: 42"
print(serialize("hello")) # "字符串: hello"
print(serialize([1, 2, 3])) # "列表: 1, 2, 3"
print(serialize({'a': 1})) # "字典: {'a': 1}"
实战场景
场景1:日志记录装饰器
import functools
import logging
from datetime import datetime
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def log_calls(logger_func=logger.info):
"""日志装饰器"""
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = datetime.now()
logger_func(f"调用 {func.__name__},参数: args={args}, kwargs={kwargs}")
try:
result = func(*args, **kwargs)
elapsed = (datetime.now() - start).total_seconds()
logger_func(f"{func.__name__} 成功,耗时 {elapsed:.3f}s,返回: {result}")
return result
except Exception as e:
elapsed = (datetime.now() - start).total_seconds()
logger_func(f"{func.__name__} 失败,耗时 {elapsed:.3f}s,异常: {e}")
raise
return wrapper
return decorator
@log_calls()
def risky_operation(x):
if x < 0:
raise ValueError("不能是负数")
return x * 2
@log_calls(logger_func=logging.debug)
def debug_operation():
return "调试信息"
场景2:重试装饰器
import functools
import time
import logging
def retry(max_attempts=3, delay=1, backoff=2, exceptions=(Exception,)):
"""
重试装饰器
Args:
max_attempts: 最大尝试次数
delay: 初始延迟(秒)
backoff: 退避倍数
exceptions: 需要重试的异常类型元组
"""
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
current_delay = delay
last_exception = None
for attempt in range(1, max_attempts + 1):
try:
return func(*args, **kwargs)
except exceptions as e:
last_exception = e
if attempt == max_attempts:
logging.error(f"{func.__name__} 重试 {max_attempts} 次后仍失败")
raise
logging.warning(
f"{func.__name__} 第 {attempt} 次失败: {e},"
f"{current_delay}s 后重试..."
)
time.sleep(current_delay)
current_delay *= backoff
raise last_exception
return wrapper
return decorator
@retry(max_attempts=3, delay=1, exceptions=(ConnectionError, TimeoutError))
def fetch_from_api(url):
"""模拟不稳定的 API 调用"""
import random
if random.random() < 0.7: # 70% 概率失败
raise ConnectionError("网络连接失败")
return "API 响应数据"
场景3:性能分析装饰器
import functools
import time
import statistics
class PerformanceMonitor:
"""性能监控器"""
_metrics = {}
@classmethod
def record(cls, func_name, duration):
if func_name not in cls._metrics:
cls._metrics[func_name] = []
cls._metrics[func_name].append(duration)
@classmethod
def report(cls):
print("\n性能报告:")
print("-" * 50)
for func, durations in cls._metrics.items():
print(f"{func}:")
print(f" 调用次数: {len(durations)}")
print(f" 平均耗时: {statistics.mean(durations):.4f}s")
print(f" 最短耗时: {min(durations):.4f}s")
print(f" 最长耗时: {max(durations):.4f}s")
if len(durations) > 1:
print(f" 标准差: {statistics.stdev(durations):.4f}s")
def monitor(func):
"""性能监控装饰器"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
try:
result = func(*args, **kwargs)
return result
finally:
duration = time.perf_counter() - start
PerformanceMonitor.record(func.__name__, duration)
return wrapper
@monitor
def matrix_multiply(a, b):
"""矩阵乘法(示例)"""
time.sleep(0.1) # 模拟计算
return [[sum(x*y for x,y in zip(row,col)) for col in zip(*b)] for row in a]
# 使用
matrix_multiply([[1,2],[3,4]], [[5,6],[7,8]])
matrix_multiply([[1,2],[3,4]], [[5,6],[7,8]])
matrix_multiply([[1,2],[3,4]], [[5,6],[7,8]])
PerformanceMonitor.report()
场景4:参数验证装饰器
import functools
def validate(**validators):
"""
参数验证装饰器工厂
Args:
validators: {参数名: 验证函数} 或 {参数名: (验证函数, 错误消息)}
"""
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# 合并位置参数和关键字参数
import inspect
sig = inspect.signature(func)
bound = sig.bind(*args, **kwargs)
bound.apply_defaults()
# 验证每个参数
for param_name, validator in validators.items():
value = bound.arguments.get(param_name)
# 支持 (验证器, 消息) 格式
if isinstance(validator, tuple):
validator_func, error_msg = validator
else:
validator_func = validator
error_msg = f"参数 {param_name} 验证失败"
if not validator_func(value):
raise ValueError(f"{error_msg}: {value}")
return func(*args, **kwargs)
return wrapper
return decorator
def in_range(min_v, max_v):
return lambda x: min_v <= x <= max_v
@validate(
age=in_range(0, 150),
name=lambda n: isinstance(n, str) and len(n) > 0,
score=(lambda s: 0 <= s <= 100, "分数必须在 0-100 之间")
)
def register(name, age, score):
return f"注册成功: {name}, {age}岁, 分数 {score}"
# 测试
try:
register("Alice", 25, 85)
print("✅ 验证通过")
except ValueError as e:
print(f"❌ {e}")
try:
register("", 25, 85) # name 验证失败
except ValueError as e:
print(f"❌ {e}")
场景5:缓存装饰器(自定义)
import functools
import hashlib
import pickle
def memoize(func):
"""自定义缓存装饰器"""
cache = {}
@functools.wraps(func)
def wrapper(*args, **kwargs):
# 构建缓存键
key = (
args,
tuple(sorted(kwargs.items()))
)
if key not in cache:
cache[key] = func(*args, **kwargs)
return cache[key]
# 添加缓存管理方法
wrapper.cache = cache
wrapper.clear_cache = lambda: cache.clear()
return wrapper
@memoize
def expensive_computation(n):
"""耗时计算"""
return sum(i * i for i in range(n))
print(expensive_computation(100000))
print(f"缓存条目: {len(expensive_computation.cache)}")
# 清除缓存
expensive_computation.clear_cache()
元类基础
什么是元类
# 类是对象的模板,元类是类的模板
# type 既是类,也是元类
# 普通类
class MyClass:
pass
print(MyClass.__class__) # <class 'type'> — 类默认由 type 创建
# type 创建的类
MyClass2 = type('MyClass2', (), {})
print(MyClass2.__class__) # <class 'type'>
# 自定义元类
class Meta(type):
def __new__(mcs, name, bases, namespace):
# mcs: 元类本身(Meta)
# name: 类名(字符串)
# bases: 父类元组
# namespace: 类的属性字典
print(f"创建类: {name}")
return super().__new__(mcs, name, bases, namespace)
class MyClass(metaclass=Meta): # 指定元类
pass
# 输出: 创建类: MyClass
元类的 new vs init
class Meta(type):
"""元类示例"""
def __new__(mcs, name, bases, namespace):
"""创建类对象时被调用"""
print(f"__new__: 创建类 {name}")
# 可以修改 namespace
namespace['created_by'] = 'Meta'
return super().__new__(mcs, name, bases, namespace)
def __init__(cls, name, bases, namespace):
"""初始化类对象时被调用"""
print(f"__init__: 初始化类 {name}")
super().__init__(name, bases, namespace)
class MyClass(metaclass=Meta):
class_attr = "属性"
# 输出:
# __new__: 创建类 MyClass
# __init__: 初始化类 MyClass
元类继承链
class BaseMeta(type):
def __new__(mcs, name, bases, namespace):
return super().__new__(mcs, name, bases, namespace)
class ChildMeta(BaseMeta): # 元类也可以继承
pass
class MyClass(metaclass=ChildMeta):
pass
# 元类继承链: ChildMeta -> BaseMeta -> type
print(ChildMeta.__mro__) # (<class '__main__.ChildMeta'>, <class '__main__.BaseMeta'>, <class 'type'>, <class 'object'>)
元类实战
实战1:自动注册类
class Registry(type):
"""注册器元类:自动将类注册到注册表"""
_registry = {}
def __new__(mcs, name, bases, namespace):
cls = super().__new__(mcs, name, bases, namespace)
# 如果类有 name 属性,使用它作为注册键
if 'name' in namespace:
mcs._registry[namespace['name']] = cls
else:
mcs._registry[name] = cls
return cls
@classmethod
def get(mcs, name):
return mcs._registry.get(name)
@classmethod
def list_all(mcs):
return list(mcs._registry.keys())
# 使用元类
class Animal(metaclass=Registry):
pass
class Dog(Animal):
name = 'dog'
def bark(self):
return "汪汪"
class Cat(Animal):
name = 'cat'
def meow(self):
return "喵喵"
# 获取注册的类
print(Registry.list_all()) # ['Dog', 'Cat']
Dog_class = Registry.get('dog')
print(Dog_class) # <class '__main__.Dog'>
print(Dog_class().bark()) # "汪汪"
实战2:ORM 字段定义
class Field:
"""字段基类"""
def __init__(self, field_type, null=True, default=None):
self.field_type = field_type
self.null = null
self.default = default
class CharField(Field):
def __init__(self, max_length=255, **kwargs):
super().__init__('VARCHAR', **kwargs)
self.max_length = max_length
class IntField(Field):
def __init__(self, **kwargs):
super().__init__('INTEGER', **kwargs)
class ModelMeta(type):
"""模型元类:自动收集字段"""
def __new__(mcs, name, bases, namespace):
cls = super().__new__(mcs, name, bases, namespace)
# 收集所有 Field 属性
cls._fields = {}
for attr_name, attr_value in namespace.items():
if isinstance(attr_value, Field):
attr_value.name = attr_name
cls._fields[attr_name] = attr_value
return cls
class Model(metaclass=ModelMeta):
"""模型基类"""
_fields = {}
class User(Model):
name = CharField(max_length=100, null=False)
age = IntField(default=0)
email = CharField(max_length=255)
# 检查字段
print("User 字段:")
for name, field in User._fields.items():
print(f" {name}: {field.field_type}({field.max_length or 'N/A'})")
# 生成的 SQL(示例)
def generate_sql(cls):
columns = []
for name, field in cls._fields.items():
col_def = f"{name} {field.field_type}"
if isinstance(field, CharField):
col_def += f"({field.max_length})"
if not field.null:
col_def += " NOT NULL"
if field.default is not None:
col_def += f" DEFAULT {field.default}"
columns.append(col_def)
return f"CREATE TABLE {cls.__name__} ({', '.join(columns)});"
print(generate_sql(User))
# CREATE TABLE User (name VARCHAR(100) NOT NULL, age INTEGER DEFAULT 0, email VARCHAR(255));
实战3:单例模式
# 方法1:元类实现单例
class SingletonMeta(type):
"""单例元类"""
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls]
class Database(metaclass=SingletonMeta):
def __init__(self):
print("数据库连接已建立")
def query(self, sql):
return f"执行: {sql}"
db1 = Database()
db2 = Database()
print(db1 is db2) # True — 同一个实例
# 方法2:装饰器实现单例
def singleton(cls):
instances = {}
@functools.wraps(cls)
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
@singleton
class Config:
def __init__(self):
self.settings = {}
def get(self, key):
return self.settings.get(key)
config1 = Config()
config2 = Config()
print(config1 is config2) # True
实战4:接口强制实现
class InterfaceMeta(type):
"""接口检查元类"""
def __new__(mcs, name, bases, namespace):
cls = super().__new__(mcs, name, bases, namespace)
# 基接口不需要检查
if not bases or bases == (object,):
return cls
# 检查是否实现了所有抽象方法
for base in bases:
if hasattr(base, '_abstract_methods'):
for method in base._abstract_methods:
if method not in namespace or not callable(namespace[method]):
raise TypeError(
f"类 {name} 必须实现抽象方法 {method}"
)
return cls
def abstract_method(func):
"""抽象方法装饰器"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
raise NotImplementedError(f"方法 {func.__name__} 未实现")
return wrapper
class IUserRepository(metaclass=InterfaceMeta):
"""用户仓储接口"""
_abstract_methods = {'get_by_id', 'save', 'delete'}
# 正确实现
class UserRepository(IUserRepository):
def get_by_id(self, id):
return {"id": id, "name": "User"}
def save(self, user):
print(f"保存用户: {user}")
def delete(self, id):
print(f"删除用户: {id}")
# 错误实现(会报错)
try:
class BadRepository(IUserRepository):
def get_by_id(self, id):
return {}
# 缺少 save 和 delete
pass
print("不会执行到这里")
except TypeError as e:
print(f"错误: {e}")
装饰器 vs 元类
对比表
| 特性 | 装饰器 | 元类 |
|---|---|---|
| 作用对象 | 函数、类 | 仅类 |
| 注入时机 | 调用时(运行时) | 定义时(类创建时) |
| 灵活性 | 更灵活,参数化控制 | 更强大,控制类创建 |
| 复杂度 | 简单直观 | 复杂难懂 |
| 继承 | 不影响继承 | 继承的类也受元类控制 |
| 使用频率 | 非常常见 | 较少使用 |
选型指南
# ✅ 用装饰器的场景
# 1. 为函数/方法添加横切关注点(日志、缓存、计时)
# 2. 参数验证和预处理
# 3. 运行时修改函数行为
# 4. 需要参数化控制
# ✅ 用元类的场景
# 1. 在类定义时修改类结构
# 2. 自动注册类
# 3. 确保接口实现
# 4. ORM 模型的字段收集
# 5. 需要所有子类都受影响
# ❌ 避免元类的情况
# 1. 装饰器能完成时不用元类
# 2. 项目其他人不熟悉元类
# 3. 需要频繁调试的场景
替代方案:类组合
# 很多时候组合优于继承,元类也可以用装饰器替代
# 元类方案
class AutoPropertyMeta(type):
def __new__(mcs, name, bases, namespace):
cls = super().__new__(mcs, name, bases, namespace)
# 自动将 _xxx 属性转换为 @property
for attr_name in list(namespace.keys()):
if attr_name.startswith('_') and not attr_name.startswith('__'):
public_name = attr_name[1:]
if public_name not in namespace:
value = namespace.pop(attr_name)
namespace[public_name] = property(lambda self: value)
return cls
# 装饰器替代方案
def auto_property(cls):
"""类装饰器版本的自动 property"""
for attr_name in list(vars(cls).keys()):
if attr_name.startswith('_') and not attr_name.startswith('__'):
public_name = attr_name[1:]
if public_name not in cls.__dict__:
value = getattr(cls, attr_name)
delattr(cls, attr_name)
setattr(cls, public_name, property(lambda self, v=value: v))
return cls
@auto_property
class Config:
_debug = True
_version = "1.0"
print(Config().debug) # True
print(Config().version) # "1.0"
排错指南
常见错误与解决方案
错误1:装饰器顺序不对
def deco1(func):
def wrapper(*args):
print("deco1")
return func(*args)
return wrapper
def deco2(func):
def wrapper(*args):
print("deco2")
return func(*args)
return wrapper
# ❌ 装饰器顺序影响输出
@deco1
@deco2
def test():
print("test")
test()
# 输出:
# deco1
# deco2
# test
# ✅ 从下往上理解:先执行 @deco2,再执行 @deco1
错误2:装饰器丢失元信息
import functools
# ❌ 不使用 wraps
def bad_decorator(func):
def wrapper(*args):
return func(*args)
return wrapper
@bad_decorator
def my_func():
"""文档"""
pass
print(my_func.__name__) # "wrapper" ← 错误!
# ✅ 使用 wraps
def good_decorator(func):
@functools.wraps(func) # 保留元信息
def wrapper(*args):
return func(*args)
return wrapper
@good_decorator
def my_func2():
"""文档"""
pass
print(my_func2.__name__) # "my_func2" ← 正确!
错误3:元类继承问题
class MetaA(type):
def __new__(mcs, name, bases, namespace):
print(f"MetaA 创建 {name}")
return super().__new__(mcs, name, bases, namespace)
class MetaB(MetaA): # MetaB 继承 MetaA
def __new__(mcs, name, bases, namespace):
print(f"MetaB 创建 {name}")
return super().__new__(mcs, name, bases, namespace)
# ❌ 问题:子类使用父元类
class MyClass(metaclass=MetaB):
pass
# 输出:
# MetaB 创建 MyClass
# MetaA 创建 MyClass(通过 super() 调用)
错误4:装饰器中的变量作用域
def outer():
funcs = []
for i in range(3):
# ❌ 闭包陷阱:所有函数共享同一个 i
funcs.append(lambda: i)
return funcs
# ❌ 所有函数返回值都是 2
for f in outer():
print(f(), end=" ") # 2 2 2
# ✅ 修复:使用默认参数捕获值
def outer_fixed():
funcs = []
for i in range(3):
funcs.append(lambda i=i: i) # i=i 捕获当前值
return funcs
for f in outer_fixed():
print(f(), end=" ") # 0 1 2
错误5:装饰器在类方法上的行为
class MyClass:
def __init__(self):
self.value = 0
@property
def doubled(self):
return self.value * 2
# ❌ 装饰器可能破坏 property
def old_decorator(func):
def wrapper(self):
return func(self) * 2
return wrapper
@old_decorator
@property
def value_trippled(self):
return self.value
# 问题:@property 返回的是描述符,不是可调用的函数
# ✅ 正确:装饰器需要处理描述符
def smart_decorator(func):
if isinstance(func, property):
return property(
lambda self: func.fget(self) * 2 # 包装 getter
)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
总结
核心要点
- 装饰器是函数:接受函数/类,返回增强后的函数/类
- 闭包是基础:装饰器利用闭包捕获外部状态
- @wraps 必不可少:保留原函数的
__name__、__doc__等元信息 - 元类控制类创建:在
__new__中修改类定义 - 装饰器优先:能用装饰器就别用元类
一图总结
┌─────────────────────────────────────────────────────────────────┐
│ 装饰器 vs 元类 │
├───────────────────────┬─────────────────────────────────────────┤
│ 装饰器 │ 元类 │
├───────────────────────┼─────────────────────────────────────────┤
│ @decorator │ class Foo(metaclass=Meta): │
│ def func(): │ pass │
│ pass │ │
├───────────────────────┼─────────────────────────────────────────┤
│ 运行时修改 │ 定义时修改 │
│ 函数/类 │ 仅类 │
│ 简单直观 │ 复杂强大 │
│ 非常常用 │ 谨慎使用 │
└───────────────────────┴─────────────────────────────────────────┘
常用装饰器模式
# 日志
def log(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
logging.info(f"调用 {func.__name__}")
return func(*args, **kwargs)
return wrapper
# 计时
def timer(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(f"{func.__name__}: {time.time() - start:.4f}s")
return result
return wrapper
# 重试
def retry(times=3, delay=1):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
for _ in range(times):
try:
return func(*args, **kwargs)
except:
time.sleep(delay)
raise
return wrapper
return decorator
# 缓存
def cache(func):
@functools.wraps(func)
def wrapper(*args):
if args not in wrapper.cache:
wrapper.cache[args] = func(*args)
return wrapper.cache[args]
wrapper.cache = {}
return wrapper
💡 提示: 元类和装饰器都是高级特性,优先考虑更简单的方案(如普通函数继承、组合模式)。只有在确实需要横切关注点或元编程时才使用。 📚 扩展阅读:
原创内容,版权所有。未经授权,禁止转载。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END













暂无评论内容