如何在Python中使用自定义元类装饰继承的方法?
如何在Python中使用自定义元类装饰继承的方法?
嗨,我来帮你搞定这个问题~你当前的元类只处理类自身直接定义的方法,核心原因是__new__方法里的attrs字典只包含当前类(比如示例中的B)的属性,那些从父类A继承来的fun1、fun2根本不在这个字典里。要让元类也装饰继承的方法,我们得主动去遍历所有基类的方法,把它们捞出来处理。
下面是修改后的元类实现,我会一步步给你解释关键点:
import types from abc import ABC, ABCMeta class DecoMeta(ABCMeta): """ 用于装饰方法的元类 """ def __new__(mcs, name: str, bases: tuple, attrs: dict): # 第一步:遍历所有基类,处理继承来的方法 for base in bases: # 遍历基类的所有属性,筛选出未被装饰的普通方法 for attr_name, attr_value in base.__dict__.items(): # 排除特殊方法(以__开头的)、已经被装饰过的方法 if (isinstance(attr_value, types.FunctionType) and not hasattr(attr_value, '_decorated') and not attr_name.startswith('__')): # 把装饰后的方法存入attrs,这样当前类会继承这个装饰后的版本 attrs[attr_name] = mcs.deco(attr_value) # 第二步:处理当前类自身定义的方法 for attr_name, attr_value in attrs.items(): if isinstance(attr_value, types.FunctionType) and not hasattr(attr_value, '_decorated'): attrs[attr_name] = mcs.deco(attr_value) return super().__new__(mcs, name, bases, attrs) @classmethod def deco(mcs, func): """ 具体的装饰逻辑 """ # 先判断是否已经被装饰过,避免重复装饰 if hasattr(func, '_decorated'): return func async def wrapper(*args, **kwargs): print(f"[装饰器日志] 正在执行方法: {func.__name__}") result = await func(*args, **kwargs) return result # 给装饰后的函数加个标记,标记已被装饰 wrapper._decorated = True # 保留原函数的名称等信息,方便调试 wrapper.__name__ = func.__name__ wrapper.__doc__ = func.__doc__ return wrapper
关键细节说明:
- 遍历基类方法:通过
base.__dict__获取基类直接定义的方法,确保我们能拿到父类A里的fun1和fun2。如果你的继承层级更深(比如Abstract1里也有方法),可以改成递归遍历所有祖先类(我后面会补充这个写法)。 - 防重复装饰:给装饰后的函数添加
_decorated标记,这样即使子类再次使用这个元类,也不会重复装饰已经处理过的方法,避免逻辑冗余。 - 排除特殊方法:通过
not attr_name.startswith('__')跳过__init__、__str__这类特殊方法,如果需要装饰它们,去掉这个判断即可。
处理多层继承的扩展写法
如果你的类有多层继承(比如Abstract1里也定义了方法),可以把遍历基类的逻辑改成递归,确保所有层级的继承方法都能被处理:
def _get_all_inherited_methods(bases): """ 递归获取所有基类的方法 """ inherited_methods = {} for base in bases: # 先递归处理当前基类的父类 inherited_methods.update(_get_all_inherited_methods(base.__bases__)) # 再处理当前基类的方法 for attr_name, attr_value in base.__dict__.items(): if isinstance(attr_value, types.FunctionType) and not attr_name.startswith('__'): inherited_methods[attr_name] = attr_value return inherited_methods # 然后在元类的__new__里替换成这个函数: all_inherited_methods = _get_all_inherited_methods(bases) for attr_name, attr_value in all_inherited_methods.items(): if not hasattr(attr_value, '_decorated'): attrs[attr_name] = mcs.deco(attr_value)
测试验证
用你的类结构测试一下,运行下面的代码就能看到所有方法都被装饰了:
class Abstract1(ABC): pass class A(Abstract1): async def fun1(self): print("执行fun1") return "fun1的返回值" async def fun2(self): print("执行fun2") return "fun2的返回值" class B(A, metaclass=DecoMeta): async def hello(self): print("执行hello") return "hello的返回值" # 运行测试 import asyncio async def main(): b_instance = B() await b_instance.fun1() await b_instance.fun2() await b_instance.hello() asyncio.run(main())
运行后会输出:
[装饰器日志] 正在执行方法: fun1 执行fun1 [装饰器日志] 正在执行方法: fun2 执行fun2 [装饰器日志] 正在执行方法: hello 执行hello
这样改完,你的元类就可以完美装饰所有继承来的方法啦~
备注:内容来源于stack exchange,提问作者Shrey Patel
相关产品推荐
相关产品推荐

