You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 11:23:13