【问题标题】:How to dynamically override __setitem__? (no subclass)如何动态覆盖 __setitem__? (无子类)
【发布时间】:2012-02-14 17:30:14
【问题描述】:

我无法在 Python2.7 中覆盖某些内置函数,例如 '__setitem__'(尽管在我测试过的以前版本中也会发生同样的情况)

虽然我知道通过子类化很容易做到这一点,但这不是我想要的,我需要能够动态覆盖这些方法。

显然,当我的类是 'object' 的子类时,被覆盖的方法总是最终调用原来的方法,但当我的类不是 'object ',它的工作原理:

>>> def new_implementation(k, v):
...     print 'New implementation'
...

### class that extends object
>>> class ExtendsObject(object):
...     def __setitem__(self, k, v):
...             print 'ExtendsObject implementation'
...



### Checking implementation
>>> obj = ExtendsObject()
>>> obj[0]=0
ExtendsObject implementation

### trying to override setitem, no success
>>> obj.__setitem__ = new_implementation
>>> obj[0]=0
ExtendsObject implementation




### class that does NOT extends object
>>> class DoesNotExtend:
...     def __setitem__(self, k, v):
...             print 'DoesNotExtend implementation'
...

### Checking implementation
>>> obj_2 = DoesNotExtend()
>>> obj_2[0]=0
DoesNotExtend implementation

### overriding now works!
>>> obj_2.__setitem__ = new_implementation
>>> obj_2[0]=0
New implementation

出于某种原因,对象似乎对这些内置函数使用了一些不同的方法解析顺序。

这是一个错误吗?我做错了吗?

【问题讨论】:

    标签: python overriding python-2.7 built-in


    【解决方案1】:

    对于旧式类,每次需要时都会在实例上查找特殊方法。新式类仅在实例的 type 上查找特殊方法,而不是在实例的字典本身中查找 - 这就是您看到所见行为的原因。

    (如果你不知道——新式类是直接或间接派生自object 的类。)

    【讨论】:

    • 出于性能原因我假设?我想没有办法解决这个问题,除了在我想覆盖那些时使用旧式类......
    • @campos.ddc:我强烈建议不要使用旧式类。可能有办法解决这个问题,但我只会告诉你,如果你告诉我你真正想要达到什么目标。
    • 基本上,我有一个“监听器”的东西,我可以在其中注册一个函数,以便在调用另一个函数时调用。每当我的清单被修改时,我都想做点什么。这个监听器是通用的,它需要一个实例,一个方法名,以及之后要调用的目标方法
    • @campos.ddc:说实话,我不太明白你的设计。也许你可以问另一个问题,用一些代码详细说明设计?
    【解决方案2】:

    正如Sven Marnach 所说,问题在于对于新型类,索引赋值使用 定义的__setitem__。但要绕过这个问题并不难。通常情况下,解决方案涉及another level of indirection。这不是一个伟大的设计,但它似乎是做你想做的事情的明显方法:

    >>> class Foo(object):
    ...     def __setitem__(self, k, v):
    ...         return self._instance_setitem(k, v)
    ...     def _instance_setitem(self, k, v):
    ...         print 'old setitem'
    ... 
    >>> def new_setitem(self, k, v):
    ...     print 'new setitem'
    ... 
    >>> f[0] = 0
    old setitem
    >>> f._instance_setitem = types.MethodType(new_setitem, f, Foo)
    >>> f[0] = 0
    new setitem
    

    【讨论】:

      猜你喜欢
      • 2011-01-04
      • 2023-03-17
      • 1970-01-01
      • 1970-01-01
      • 2013-12-12
      • 2016-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多