Python __index__特殊方法

时间:2014-12-12 17:50:59

标签: 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

thing如何知道在列表访问时将自己表示为1,而不是由dict访问?这两种魔术方法都不能通过__getitem__吗?列表显示的用法可以通过__int__来代替__index__ raison d'être是什么?

3 个答案:

答案 0 :(得分:12)

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

  

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必须是整数。