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

使用元类装饰类中所有函数时遇TypeError错误求助

问题:批量给类函数应用装饰器时出现TypeError错误

尝试用元类给类中所有非__init__方法批量添加装饰器,代码框架如下:

class myMetaClass(type):
    def __new__(cls, name, bases, local):
        for attr in local:
            value = local[attr]
            if callable(value) and attr != '__init__':
                local[attr] = log_decorator(local['Variable'], value)
        return super().__new__(cls, name, bases, local)


class log_decorator():
    def __init__(self, Variable, func):
        self.Variable = Variable
        self.func = func

    def __call__(self, *args, **kargs):
        start_time = time.time()
        self.func(*args, **kargs)
        end_time = time.time()


class Test(metaclass = myMetaClass):
    Variable = Some_Class
    check_test = Some_Class

    def __init__(self, **args):
        self.connect = Some_Class(**args)

    def A(self, a, b):
        self.connect.abc
        pass

调用代码:

def Flow():
    test = Test(**args)
    test.A(a, b)

运行时抛出异常:

TypeError:A() missing 1 required positional argument: 'self'

错误原因

Python的实例方法依赖描述符协议实现自动绑定self参数。当用log_decorator实例替换原方法后,这个装饰器实例没有实现描述符的__get__方法,导致访问test.A时,无法将test实例绑定到原方法的self参数上。直接调用装饰器的__call__方法时,原函数A缺少必需的self参数,因此报错。


解决方案

方案1:给类装饰器添加描述符支持

修改log_decorator类,实现__get__方法来绑定实例:

import time
from functools import partial

class log_decorator:
    def __init__(self, Variable, func):
        self.Variable = Variable
        self.func = func

    def __get__(self, instance, owner):
        # 将实例绑定到__call__方法,返回绑定后的可调用对象
        return partial(self.__call__, instance)

    def __call__(self, instance, *args, **kwargs):
        start_time = time.time()
        self.func(instance, *args, **kwargs)  # 传入instance作为原方法的self
        end_time = time.time()
        # 可添加耗时打印等逻辑
        print(f"方法 {self.func.__name__} 执行耗时: {end_time - start_time:.4f} 秒")

方案2:改用函数式装饰器

函数式装饰器更适配Python的方法绑定逻辑,代码更简洁:

import time
from functools import wraps

def log_decorator(Variable):
    def decorator(func):
        @wraps(func)  # 保留原函数的元信息(如名称、文档字符串)
        def wrapper(self, *args, **kwargs):
            start_time = time.time()
            result = func(self, *args, **kwargs)
            end_time = time.time()
            print(f"方法 {func.__name__} 执行耗时: {end_time - start_time:.4f} 秒")
            return result
        return wrapper
    return decorator

class myMetaClass(type):
    def __new__(cls, name, bases, local):
        for attr in local:
            value = local[attr]
            if callable(value) and attr != '__init__':
                local[attr] = log_decorator(local['Variable'])(value)
        return super().__new__(cls, name, bases, local)

更优实现方式:用类装饰器替代元类

相比元类,类装饰器可读性更强、更易维护,同样能实现批量给方法加装饰器的需求:

import time
from functools import wraps

def log_decorator(Variable):
    def decorator(func):
        @wraps(func)
        def wrapper(self, *args, **kwargs):
            start_time = time.time()
            result = func(self, *args, **kwargs)
            end_time = time.time()
            print(f"方法 {func.__name__} 执行耗时: {end_time - start_time:.4f} 秒")
            return result
        return wrapper
    return decorator

def apply_decorator_to_methods(decorator, exclude=['__init__']):
    def class_decorator(cls):
        # 遍历类的属性,给符合条件的方法添加装饰器
        for attr_name, attr_value in cls.__dict__.items():
            if callable(attr_value) and attr_name not in exclude:
                setattr(cls, attr_name, decorator(cls.Variable)(attr_value))
        return cls
    return class_decorator

# 使用类装饰器批量添加
@apply_decorator_to_methods(log_decorator)
class Test:
    Variable = Some_Class
    check_test = Some_Class

    def __init__(self, **args):
        self.connect = Some_Class(**args)

    def A(self, a, b):
        self.connect.abc
        pass

内容的提问来源于stack exchange,提问作者Qian

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 19:31:03