使用元类装饰类中所有函数时遇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
相关产品推荐
相关产品推荐

