Python包装类如何覆盖属性,使被包装类方法使用该属性?
问题与解决方案
问题描述
定义类A,包含@property装饰的prop属性,以及依赖该属性的method方法和other_prop属性:
class A: @property def prop(self) -> int: return 1 @property def other_prop(self) -> int: return self.prop * 4 # 依赖self.prop def method(self) -> int: return self.prop * 2 # 依赖self.prop
随后定义包装类B,接收A的实例,重写prop属性,并通过__getattr__将未定义的属性委托给A:
class B: def __init__(self, a: A): self._a = a @property def prop(self) -> int: return 2 # 重写A的prop属性 def __getattr__(self, attr): return getattr(self._a, attr) # 委托未定义的属性给A实例
实际调用时出现不符合预期的结果:
- 调用
b.method()期望得到4(使用B的prop计算),但实际返回2(因为A的method中self指向原A实例,使用A的prop) - 访问
b.other_prop期望得到8,实际返回4,原因同上
需求限制:
- 不能使用继承
- 不想在B中复制A的method或other_prop的逻辑
- 尝试过
__getattribute__但无效
解决方案
核心问题是:从A实例获取的方法/属性,其内部的self仍指向原A实例,而非B实例。我们需要在委托时,将这些可调用对象的self参数替换为B实例。
修改B类的__getattr__方法,针对方法和property做包装处理:
import functools class A: @property def prop(self) -> int: return 1 @property def other_prop(self) -> int: return self.prop * 4 def method(self) -> int: return self.prop * 2 class B: def __init__(self, a: A): self._a = a @property def prop(self) -> int: return 2 def __getattr__(self, attr): attr_obj = getattr(self._a, attr) # 处理方法:将方法绑定到B实例作为self参数 if callable(attr_obj): return functools.partial(attr_obj, self) # 处理property:调用其getter时传入B实例 elif isinstance(attr_obj, property): return attr_obj.fget(self) # 其他普通属性直接返回 return attr_obj
原理说明
- 方法处理:使用
functools.partial将A的方法与B实例绑定,调用方法时,self参数自动替换为B实例,方法内部的self.prop会访问B的prop属性。 - Property处理:直接调用A中property的
fget方法,并传入B实例作为self,让property的计算逻辑使用B的prop属性。
测试验证:
a = A() b = B(a) print(b.method()) # 输出4,符合预期 print(b.other_prop) # 输出8,符合预期
内容的提问来源于stack exchange,提问作者Raquel
相关产品推荐
相关产品推荐

