英文:
How to wrap __getitem__ method correctly to keep square brackets functionality
问题
我有一个类B,它包装了类A的`__getitem__`方法:
    def my_decorator(method):
        def wrapper(*args, **kwargs):
            print('Decorator')
            method(*args, **kwargs)
        return wrapper
    class A:
        def __getitem__(self, idx):
            print(idx)
    
    class B:
        def __init__(self):
            self._a = A()
            self._a.__getitem__ = my_decorator(self._a.__getitem__)
    
        def get_a(self, idx):
            self._a[idx]
    
    
    b = B()
    b.get_a(0)
我期望的输出应该是:
    Decorator
    0
但是实际上我得到的输出是:
    0
如果我将`get_a`方法改为如下所示,我可以得到期望的行为:
    def get_a(self, idx):
        self._a.__getitem__(idx)
似乎包装`__getitem__`方法并不影响使用方括号的访问方式。有没有办法使原始代码在使用方括号访问时也能正常工作?我不想修改`get_a`的实现方式。
英文:
I have a class B that wraps the the __getitem__ method of class A:
def my_decorator(method):
    def wrapper(*args, **kwargs):
        print('Decorator')
        method(*args, **kwargs)
    return wrapper
class A:
    def __getitem__(self, idx):
        print(idx)
class B:
    def __init__(self):
        self._a = A()
        self._a.__getitem__ = my_decorator(self._a.__getitem__)
    def get_a(self, idx):
        self._a[idx]
b = B()
b.get_a(0)
I would expect the following output:
Decorator
0
But instead I just get:
0
If I change get_a method as follows, I get the expected behaviour:
def get_a(self, idx):
    self._a.__getitem__(idx)
It seems that wrapping the __getitem__ method doesn't affect the access with square brackets. Is there any way to make the original code work with square brackets access? I don't want to modify the implementation of get_a.
答案1
得分: 4
self._a[idx] 相当于 type(self._a).__getitem__(idx),而不是 self._a.__getitem__(idx)。你定义的实例属性 __getitem__ 在 [] 语法中会被忽略。
你需要定义一个继承自 A 的子类,重写 __getitem__ 方法。
class A:
    def __getitem__(self, idx):
        print(idx)
class SubA(A):
    def __getitem__(self, idx):
        print('Decorator')
        return super().__getitem__(idx)
class B:
    def __init__(self):
        self._a = SubA()
    def get_a(self, idx):
        self._a[idx]
b = B()
b.get_a(0)
(请注意:__getitem__ 应该真正返回一个值,这样的话 get_a 需要显式地返回 self._a[idx] 的值。)
英文:
self._a[idx] is equivalent to type(self._a).__getitem__(idx), not self._a.__getitem__(idx). The instance attribute __getitem__ you define is ignored by the [] syntax.
You need to define a subclass of A that overrides __getitem__.
class A:
    def __getitem__(self, idx):
        print(idx)
class SubA(A):
    def __getitem__(self, idx):
        print('"Decorator"')
        return super().__getitem__(idx)
class B:
    def __init__(self):
        self._a = SubA()
    def get_a(self, idx):
        self._a[idx]
b = B()
b.get_a(0)
(Just to note: __getitem__ should really return a value, in which case get_a needs to explicitly return the value of self._a[idx].)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论