Is it possible to override __getitem__ at instance level in Python?

我的梦境 提交于 2019-12-21 03:44:26

问题


With the following code :

import types

class Foo():
    def __getitem__(self, x):
        return x

def new_get(self, x):
    return x + 1

x = Foo()
x.__getitem__ = types.MethodType(new_get, x)

x.__getitem__(42) will return 43, but x[42] will return 42.

Is there a way to override __getitem__ at instance level in Python?


回答1:


This is unfortunately, and quite surprisingly, not allowed:

For custom classes, implicit invocations of special methods are only guaranteed to work correctly if defined on an object’s type, not in the object’s instance dictionary.

Source: https://docs.python.org/3/reference/datamodel.html#special-lookup




回答2:


Don't do it...

The item lookup protocol will always recover __getitem__ from the class, it will not even look at instance __dict__. This is actually a good thing in general as doing otherwise would allow instances of the same class to be conceptually different from one another, which goes against the whole idea behind classes.

But...

Nonetheless, there are situation where this could potentially be helpful, by example when monkey-patching for test purpose.

Because the dunder is looked up directly at class level, the item lookup logic must also be updated at the class level.

A solution is thus to update __getitem__ so that it first looks for an instance-level function in the instance __dict__.

Here is an example where we are subclassing dict to allow for instance-level __getitem__.

class Foo(dict):
    def __getitem__(self, item):
        if "instance_getitem" in self.__dict__:
            return self.instance_getitem(self, item)
        else:
            super().__getitem__(item)

foo = Foo()
foo.instance_getitem = lambda self, item: item + 1
print(foo[1]) # 2


来源:https://stackoverflow.com/questions/57413453/is-it-possible-to-override-getitem-at-instance-level-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!