在新式类中实现__getitem__

时间:2012-12-31 13:51:11

标签: python python-2.7

我有这段代码:

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]

引发TypeError。

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

非常感谢! 保罗

3 个答案:

答案 0 :(得分:6)

这在Python数据模型文档中有记录:Special method lookup for new-style classes

  

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

  

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

因此,因为hash(int) hash(1)都必须工作,所以会在类型而不是实例上查找特殊方法。如果直接在对象上查找__hash__(),则hash(int)将被转换为int.__hash__(),这将失败,因为int.__hash__()是一个未绑定的方法,并且它希望被调用在int()的实际实例上(例如1);因此,对于hash(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

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

答案 1 :(得分:0)

如果对象的类是新式类,则只能查找特殊方法,而不像旧式类。您正在实例上定义__getitem__方法,这对新样式类没有影响。

答案 2 :(得分:0)

默认迭代器在新样式类中不使用__getitem__。请参阅http://grokbase.com/t/python/tutor/085k143q1r/new-style-classes-getitem-and-iteration以获取示例。似乎__getitem__的行为已随python 2.2和新类型的类型而改变