Можно ли переопределить __getitem__ на уровне экземпляра в Python?
С помощью следующего кода:
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)
вернет 43, а x[42]
вернет 42.
Есть ли способ переопределить __getitem__
на уровне экземпляра в Python?
Ответы
Ответ 1
Это, к сожалению, и, что удивительно, недопустимо:
Для пользовательских классов неявные вызовы специальных методов гарантированно работает правильно, если определено для типа объекта, а не в словарь экземпляров объектов.
Источник: https://docs.python.org/3/reference/datamodel.html#special-lookup
Ответ 2
Не делай этого...
Протокол поиска предметов всегда восстанавливает __getitem__
из класса, он даже не просматривает экземпляр __dict__
. На самом деле это хорошая вещь, так как в противном случае экземпляры одного и того же класса будут концептуально отличаться друг от друга, что противоречит всей идее классов.
Но...
Тем не менее, существуют ситуации, когда это может быть полезно, например, при исправлении обезьян в целях тестирования.
Из-за того, что dunder ищется непосредственно на уровне класса, логика поиска предметов также должна обновляться на уровне класса.
Таким образом, решение состоит в том, чтобы обновить __getitem__
, чтобы он сначала искал функцию уровня экземпляра в экземпляре __dict__
.
Вот пример, в котором мы создаем подклассы dict
для разрешения уровня экземпляра __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