如何让类装饰器适配实例方法并支持额外属性与__self__利用?
类装饰器适配实例方法的问题与解决方案
问题背景
现有如下类装饰器实现:
class Foo: def __init__(self, func): self.func = func self.variable1 = 1 self.variable2 = 2 def __call__(self, *args, **kwargs): return self.func(*args, **kwargs)
该装饰器直接用于实例方法时会报错:
class Bar: @Foo def dance(self): return 0 Bar().dance() # TypeError: missing 1 required positional argument: 'self'
问题1:能否让dance()表现得像内置绑定方法,同时允许访问Bar().dance.variable1这类额外变量?
可以实现,核心是让Foo类遵循描述符协议,通过实现__get__方法处理实例属性的绑定逻辑,同时保留对装饰器实例属性的访问能力。
修改后的Foo类代码:
class Foo: def __init__(self, func): self.func = func self.variable1 = 1 self.variable2 = 2 def __get__(self, instance, owner): # 类层面访问(如Bar.dance)时返回装饰器自身 if instance is None: return self # 创建绑定方法包装类,模拟内置绑定行为 class BoundMethod: def __call__(self, *args, **kwargs): # 自动传入实例作为第一个参数,模拟绑定方法 return self.func(instance, *args, **kwargs) # 代理属性访问到原装饰器实例 def __getattr__(self, name): return getattr(self.__foo_instance, name) bound = BoundMethod() bound.func = self.func bound.__foo_instance = self bound.__self__ = instance # 模拟内置绑定方法的__self__属性 return bound def __call__(self, *args, **kwargs): # 类层面直接调用装饰器时执行(如Foo(func)()) return self.func(*args, **kwargs)
测试验证:
class Bar: @Foo def dance(self): return 0 b = Bar() print(b.dance()) # 输出:0(正常调用,自动传入self) print(b.dance.variable1) # 输出:1(访问装饰器的额外变量) print(b.dance.__self__) # 输出:<__main__.Bar object at 0x...>(模拟内置绑定方法的__self__)
问题2:未装饰的Bar().dance拥有指向Bar对象的__self__属性,能否在variable1中利用该属性?
可以,但不能在Foo的__init__阶段直接使用(因为装饰器在类定义时初始化,此时还没有Bar实例),需要将variable1设计为动态属性,在绑定方法被访问时再获取__self__(即Bar实例)。
修改后的Foo类代码(以动态生成variable1为例):
class Foo: def __init__(self, func): self.func = func self.variable2 = 2 def __get__(self, instance, owner): if instance is None: return self class BoundMethod: def __call__(self, *args, **kwargs): return self.func(instance, *args, **kwargs) # 将variable1设为动态属性,利用绑定的实例(__self__) @property def variable1(self): return f"绑定实例ID:{id(instance)},实例属性:{instance.__dict__}" # 代理其他属性到原装饰器实例 def __getattr__(self, name): return getattr(self.__foo_instance, name) bound = BoundMethod() bound.func = self.func bound.__foo_instance = self bound.__self__ = instance return bound def __call__(self, *args, **kwargs): return self.func(*args, **kwargs)
测试验证:
class Bar: def __init__(self, name): self.name = name @Foo def dance(self): return 0 b1 = Bar("Alice") print(b1.dance.variable1) # 输出:绑定实例ID:xxx,实例属性:{'name': 'Alice'} b2 = Bar("Bob") print(b2.dance.variable1) # 输出:绑定实例ID:yyy,实例属性:{'name': 'Bob'}
内容的提问来源于stack exchange,提问作者feiyang472
相关产品推荐
相关产品推荐

