>>> class Thing(object):
... def __index__(self):
... return 1
...
>>> thing = Thing()
>>> list_ = ['abc', 'def', 'ghi']
>>> list_[thing]
'def'
>>> dict_ = {1: 'potato'}
>>> dict_[thing]
# KeyError
thing
如何知道在列表访问时将自己表示为1,而不是由dict访问?这两种魔术方法都不能通过__getitem__
吗?列表显示的用法可以通过__int__
来代替__index__
的 raison d'être是什么?
答案 0 :(得分:12)
Dict和List没有以同样的方式实现
__getitem__
。
但是,我想补充一点信息。根据{{3}}:
object.__index__(self)
调用实现
operator.index()
,每当Python需要无损地将数字对象转换为整数对象时(如 在切片中,或在内置bin()
,hex()
和oct()
中 功能)。此方法的存在表示数字对象 是整数类型。必须返回一个整数。
我加粗的部分非常重要。列表上的索引和切片都由相同的方法处理(即__getitem__
)。因此,如果调用Thing.__index__
进行切片,则同样会调用它进行索引,因为我们使用相同的方法。这意味着:
list_[thing]
大致相当于:
list_[thing.__index__()]
但是对于字典,Thing.__index__
没有被调用(没有理由调用它,因为你不能切片字典)。相反,做dict_[thing]
告诉Python在字典中查找thing
实例本身的密钥。由于这不存在,因此会引发KeyError
。
也许演示会有所帮助:
>>> 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'
>>>
至于为什么__index__
首先存在,原因在documentation中有详尽列出。我不会在这里重复所有这些,但基本上它是这样你可以允许任意对象作为整数,这在切片以及一些其他应用程序中是必需的。
答案 1 :(得分:9)
Dict和List没有以同样的方式实现__getitem__
。 Dict对象使用__eq__
个对象上的比较(__hash__
)作为__getitem__
中使用的键。
要使Thing
可用于dict,你必须同时实现hash和eq。
答案 2 :(得分:0)
进一步理解它的另一个例子,这里_MolsToGridSVG采用list参数。我想将列表限制到一定程度。现在这里是python列表,必须使用切片索引。以下实现解决了它。基本上这里的索引正在用于Python List。
def __index__(self):
return 1
imagesInOneFile = int(len(smilesMolList) / noOfFiles)
svg = Draw._MolsToGridSVG(smilesMolList[:imagesInOneFile.__index__()], subImgSize=(400, 200), molsPerRow=2)
还需要记住imagesInOneFile
必须是整数。