如何正确包装__getitem__方法以保留方括号访问功能?
问题解析与解决方案
问题原因
Python 对特殊方法(如__getitem__)的调用采用类层面优先查找机制:当使用obj[key]这种方括号语法时,解释器会直接去obj.__class__中查找__getitem__方法,完全绕过实例自身的属性字典。你之前直接给self._a实例赋值__getitem__,并不会被方括号访问触发,只有直接调用self._a.__getitem__(idx)时才会用到这个实例属性。
解决方案(无需修改get_a方法)
方案1:创建A的子类并装饰__getitem__
通过定义A的子类,在子类中装饰__getitem__,然后实例化子类作为self._a。这种方式不会影响原A类的其他实例:
def my_decorator(method): def wrapper(*args, **kwargs): print('Decorator') return method(*args, **kwargs) return wrapper class A: def __getitem__(self, idx): print(idx) class B: def __init__(self): # 定义装饰后的A子类 class DecoratedA(A): @my_decorator def __getitem__(self, idx): return super().__getitem__(idx) self._a = DecoratedA() def get_a(self, idx): self._a[idx] b = B() b.get_a(0)
方案2:动态修改实例的所属类(仅影响当前实例)
如果只想给self._a这一个实例添加装饰器,不影响其他A实例,可以动态创建一个临时子类并替换实例的__class__属性:
def my_decorator(method): def wrapper(*args, **kwargs): print('Decorator') return method(*args, **kwargs) return wrapper class A: def __getitem__(self, idx): print(idx) class B: def __init__(self): self._a = A() # 为当前实例创建专属临时子类 temp_subclass = type(f"DecoratedA_{id(self._a)}", (A,), {}) temp_subclass.__getitem__ = my_decorator(temp_subclass.__getitem__) # 替换实例的所属类 self._a.__class__ = temp_subclass def get_a(self, idx): self._a[idx] b = B() b.get_a(0)
方案3:全局修改A类的__getitem__(谨慎使用)
如果所有A实例都需要这个装饰器,可以直接修改A类的方法,但这会影响所有A的实例:
def my_decorator(method): def wrapper(*args, **kwargs): print('Decorator') return method(*args, **kwargs) return wrapper class A: def __getitem__(self, idx): print(idx) # 全局装饰A类的__getitem__ A.__getitem__ = my_decorator(A.__getitem__) class B: def __init__(self): self._a = A() def get_a(self, idx): self._a[idx] b = B() b.get_a(0)
内容的提问来源于stack exchange,提问作者danst_18
相关产品推荐
相关产品推荐

