5

我有这个代码:

class A:
    def __init__(self):
        def method(self, item):
            print self, ": Getting item", item
        self.__getitem__ = types.MethodType(method, self, self.__class__)

class B(object):
    def __init__(self):
        def method(self, item):
            print self, ": Getting item", item
        self.__getitem__ = types.MethodType(method, self, self.__class__)

然后这工作正常:

a = A()
a[0]

但这不会:

b = B()
b[0]

引发类型错误。

我发现新式类在类 __dict__ 而不是实例 __dict__ 中寻找魔术方法。这是正确的吗?为什么会这样?你知道任何解释背后想法的文章吗?我尝试了 RTFM,但可能不是正确的,或者没有抓住东西......

非常感谢!保罗

4

3 回答 3

6

这记录在 Python 数据模型文档中:新式类的特殊方法查找

对于新式类,特殊方法的隐式调用只有在对象类型上定义时才能保证正常工作,而不是在对象的实例字典中。

这种行为背后的基本原理在于许多特殊方法,例如__hash__()__repr__()由所有对象实现,包括类型对象。如果这些方法的隐式查找使用常规查找过程,则在类型对象本身上调用它们时会失败[.]

因此,因为两者都hash(int) 必须 hash(1)工作,所以在类型而不是实例上查找特殊方法。如果__hash__()直接在对象上查找,hash(int)将被转换为int.__hash__(),这将失败,因为它是一个未绑定的方法,并且它期望在(eg )int.__hash__()的实际实例上调用;所以对于,应该改为:int()1hash(int)type.__hash__()

>>> hash(1) == int.__hash__(1)
True
>>> hash(int) == type.__hash__(int)
True
>>> int.__hash__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: descriptor '__hash__' of 'int' object needs an argument

这是一个向后不兼容的更改,因此它仅适用于新样式对象。

于 2012-12-31T14:08:22.550 回答
0

特殊方法仅在对象的类是新式类时才针对其进行查找,这与旧式类不同。您正在__getitem__实例上定义方法,这对新样式类没有影响。

于 2012-12-31T13:59:56.763 回答
0

默认迭代器不在__getitem__新样式类中使用。有关示例,请参见http://grokbase.com/t/python/tutor/085k143q1r/new-style-classes-getitem-and-iteration。似乎__getitem__随着 python 2.2 和新样式的类的行为发生了变化

于 2012-12-31T14:08:04.193 回答