【问题标题】:Is it possible to override __getitem__ at instance level in Python?是否可以在 Python 的实例级别覆盖 __getitem__ ?
【发布时间】:2019-12-16 05:10:18
【问题描述】:

使用以下代码:

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。

有没有办法在 Python 中的实例级别覆盖 __getitem__

【问题讨论】:

  • 我确定有
  • 无论如何你都不想这样做。从概念上讲,具有不同方法定义的对象不再是类的一部分。
  • 如果你想要完整的故事:我想计时一些过程,所以基本上,我通过添加代码来覆盖我想要计时的实例的方法来计时对这些方法的调用,特别是,我想要打电话给__getitem__。 (这个想法是修改一个对象,通过一些现有的代码传递它并记录它在每次调用方法时所花费的时间)。
  • Related: “implicit uses of special methods always rely on the class-level binding of the special method” (文本实际上是错误的;并非所有特殊方法都依赖于类级绑定,但你不能指望其中任何一个不这样做,它可能会因版本而异,因为它们中的任何一个都不正式支持实例级别的重新绑定)。

标签: python monkeypatching


【解决方案1】:

别这样……

项目查找协议将始终从类中恢复__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:
            return super().__getitem__(item)

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

【讨论】:

  • 这是一个很好的建议,但我认为它对我的情况没有帮助。这个想法是我想在一些不是我写的代码中计时__getitem__ 的一些调用。所以我拿了一个对象,修改它的__getitem__方法来记录每次调用的时间,然后把它传递给不是我写的代码。我只需要在类级别而不是实例级别上进行操作。
  • @StatisticDean 上面的sn-p代码告诉你如何用继承做你想做的事
【解决方案2】:

不幸的是,令人惊讶的是,这是不允许的:

对于自定义类,特殊方法的隐式调用仅 如果在对象的类型上定义,则保证正常工作,而不是在 对象的实例字典。

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

【讨论】:

  • 在文档上搜索了一下,找不到这个信息。非常感谢 !我想我必须找到另一种解决方案才能实现我想要的解决方案。
  • 尝试一下:x.__class__.__bases__.__getitem__ = new_get 给出了AttributeError: 'tuple' object attribute '__getitem__' is read-only,所以你是对的。
  • 这并不完全是不幸的;如果他们允许,例如,您可以为序列类本身下标,例如list[2],而不是立即拒绝它是荒谬的,它必须检查list.__getitem__ 以确保它被传递一个list 实例,而不是类本身,每次 .在课堂上查找它只会以其他方式加快速度(99.9% 的时间来自课堂上的 C 级插槽,但您必须每次检查实例字典以确保它不是被覆盖的
  • @ShadowRanger 是的,不幸的是,对于 OP 的问题。
猜你喜欢
  • 2010-09-28
  • 1970-01-01
  • 2019-02-24
  • 2020-07-02
  • 1970-01-01
  • 2020-12-28
  • 2019-09-19
  • 2013-10-19
  • 1970-01-01
相关资源
最近更新 更多