在Python中是否可以在实例级别重写_getitem __?

在Python中是否可以在实例级别重写_getitem __?,python,monkeypatching,Python,Monkeypatching,使用以下代码: 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.\uu getitem\uu42将返回43,但x[42]将返回42 在Python中,有没有一种方法可以在实例级别重写\uuu getit

使用以下代码:

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.\uu getitem\uu42
将返回43,但
x[42]
将返回42


在Python中,有没有一种方法可以在实例级别重写
\uuu getitem\uuu

对于自定义类,特殊方法的隐式调用仅限于 如果在对象的类型上定义,而不是在 对象的实例字典

来源:

不要这样做。。。 项查找协议将始终从类中恢复
\uuuuu getitem\uuuuuuuuuu
,它甚至不会查看实例
\uuuuuuuu dict\uuuuuuuu
。这实际上是一件好事,因为如果不这样做,将允许同一类的实例在概念上彼此不同,这与类背后的整个思想背道而驰

但是 尽管如此,在某些情况下,这可能是有帮助的,例如,当为测试目的进行猴子补丁时

因为dunder是在类级别直接查找的,所以项查找逻辑也必须在类级别更新

因此,一种解决方案是更新
\uuuu getitem\uuuuuuu
,以便它首先在实例
\uuuu dict\uuuuu
中查找实例级函数

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
下面是一个示例,其中我们正在子类化
dict
,以允许实例级别
\uu getitem\uu

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

我肯定你无论如何都不想这么做。从概念上讲,具有不同方法定义的对象不再是类的一部分。如果您想了解全部情况:我想对某个进程计时,因此基本上,我通过添加代码来计时对这些方法的调用,从而覆盖我想计时的实例的方法,特别是,我想对
\uu getitem\uuuuu
的调用执行此操作。(其思想是修改对象,将其传递给一些现有代码,并记录每次调用方法所花费的时间)。相关:(文本实际上是错误的;并不是所有的特殊方法都依赖于类级绑定,但您不能指望它们中的任何一个不依赖于类级绑定,并且它可能会随着版本的变化而变化,因为它们中的任何一个都不正式支持实例级重新绑定)。在文档上搜索了一点,但找不到此信息。非常感谢!我想我必须找到另一个解决方案来实现我想要的解决方案。尝试一下:
x.\uuuuuuu class.\uuuuuuu base.\uuuuuuu getitem\uuuuuuuu=new\uu get
给出了
属性错误:'tuple'object attributer'\uuuuuuu getitem\uuuuuuu'是只读的
,所以你是对的。这并不完全是不正确的幸运的是,如果他们允许的话,您可以自己为序列类下标,例如
list[2]
,而不是立即将其视为无意义的拒绝,它必须签入
列表。\uuu getitem\uuuu
以确保每次都传递一个
列表
实例,而不是类本身。在类上查找它还可以以其他方式加快速度(99.9%的时间来自类上的C级插槽,但每次都必须检查实例字典,以确保它不是被覆盖的<0.1%情况)@ShadowRanger是的,很不幸,这是OP的问题。这是一个很好的建议,但我认为它对我的情况没有帮助。我的想法是,我想在一些不是我写的代码中计时
\uuuuuGetItem\uuuuuuuuu
的一些调用。所以我取一个对象,修改它的
\uuuGetItem\uuuuuuuu
方法来记录每次调用的时间,然后st将其传递给非我编写的代码。我只需在类级别而不是实例级别执行该操作。@StatisticDean上面的代码片段向您展示了如何使用继承来执行您想要的操作