Python __index__特殊方法

wim*_*wim 14 python magic-methods

>>> class Thing(object):
...     def __index__(self):
...         return 1
... 
>>> thing = Thing()
>>> list_ = ['abc', 'def', 'ghi']
>>> list_[thing]
'def'
>>> dict_ = {1: 'potato'}
>>> dict_[thing]
# KeyError
Run Code Online (Sandbox Code Playgroud)

thing知道如何在列表访问时将自己表示为1,而不是由dict表示?难道两种魔术方法都没有通过__getitem__?列表中显示的用法可以通过,__int__所以无论如何,存在的理由__index__什么?

iCo*_*dez 14

当他说:@BenoîtLatinier是正确的

Dict和List没有__getitem__以同样的方式实现.

但是,我想补充一点信息.根据文件:

object.__index__(self)

称为实施operator.index(),并且无论何时需要的Python于数字对象无损转换为整数对象(如在切片,或在内置的bin(),hex()oct() 函数).此方法的存在表明数字对象是整数类型.必须返回一个整数.

我加粗的部分很重要.列表上的索引和切片都由相同的方法处理(即__getitem__).因此,如果Thing.__index__调用切片,则同样会调用索引,因为我们使用相同的方法.这意味着:

list_[thing]
Run Code Online (Sandbox Code Playgroud)

大致相当于:

list_[thing.__index__()]
Run Code Online (Sandbox Code Playgroud)

然而,对于字典,Thing.__index__没有被调用(没有理由调用它,因为你不能切片字典).相反,做的dict_[thing]是告诉Python在字典中查找thing实例本身的密钥.由于这不存在,KeyError因此提出了a .

也许演示会有所帮助:

>>> class Thing(object):
...     def __index__(self):
...         print '__index__ called!'
...         return 1
...
>>> thing = Thing()
>>> list_ = ['abc', 'def', 'ghi']
>>> list_[thing]  # __index__ is called
__index__ called!
'def'
>>>
>>> dict_ = {1: 'potato'}
>>> dict_[thing]  # __index__ is not called
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: <__main__.Thing object at 0x01ACFC70>
>>>
>>> dict_ = {thing: 'potato'} # Works if thing is a key
>>> dict_[thing]
'potato'
>>>
Run Code Online (Sandbox Code Playgroud)

至于为什么__index__首先存在,原因在PEP 0375中彻底列出.我不会在这里重复所有这些,但基本上它是这样你可以允许任意对象作为整数,这在切片以及一些其他应用程序中是必需的.


Ben*_*ier 9

Dict和List没有__getitem__以同样的方式实现.Dict对象使用对象的compare(__eq__)__hash__作为要使用的键__getitem__.

要使Thingdict可用,你必须同时实现hash和eq.