我无法覆盖 Python2.7 中的某些内置函数,例如'__setitem__'(尽管在我测试的先前版本中也是如此)
虽然我知道通过子类化很容易做到这一点,但这不是我想要的,我需要能够动态覆盖这些方法。
显然,当我的班级是“对象”的子类时,被覆盖的方法总是会调用原始方法,但是当我的班级不是“对象”时',它有效:
>>> 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
出于某种原因,对象似乎对这些内置函数使用了一些不同的方法解析顺序。
这是一个错误吗?我做错了吗?
答案 0 :(得分:5)
对于旧式类,每次需要时都会在实例上查找特殊方法。新式类只在实例的类型上查找特殊方法,而不是在实例的字典本身中查找特殊方法 - 这就是您看到所看到的行为的原因。
(如果您不知道 - 新式类是直接或间接派生自object
的类。)
答案 1 :(得分: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