Python __index__ special method Python __index__ special method python python

Python __index__ special method


@BenoîtLatinier was correct when he said:

Dict and List does not implement __getitem__ the same way.

However, I'd like to add a little more information. According to the documentation:

object.__index__(self)

Called to implement operator.index(), and whenever Python needs to losslessly convert the numeric object to an integer object (such as in slicing, or in the built-in bin(), hex() and oct() functions). Presence of this method indicates that the numeric object is an integer type. Must return an integer.

The part I bolded is important. Indexing and slicing on a list are both handled by the same method (namely, __getitem__). So, if Thing.__index__ is called for slicing, it will likewise be called for indexing since we are using the same method. This means that:

list_[thing]

is roughly equivalent to:

list_[thing.__index__()]

For the dictionary however, Thing.__index__ is not being called (there is no reason to call it since you cannot slice a dictionary). Instead, doing dict_[thing] is telling Python to find a key in the dictionary that is the thing instance itself. Since this doesn't exist, a KeyError is raised.

Perhaps a demonstration will be helpful:

>>> 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 calledTraceback (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'>>>

As for why __index__ exists in the first place, the reason is thoroughly listed in PEP 0375. I won't repeat all of it here, but basically it is so that you can allow arbitrary objects to serve as integers, which is needed in slicing as well as a few other applications.


Dict and List does not implement __getitem__ the same way. Dict objects uses a comparison (__eq__) on __hash__ of objects as key to use in __getitem__.

To make Thing usable for dict you have to implement both hash and eq.


Another example to understand it further, here _MolsToGridSVG takes a list argument. I wanted to limit the list to some length. Now here for python list, slice indices have to be used. The following implementation solved it. Basically here index is getting used for Python List.

def __index__(self):    return 1imagesInOneFile = int(len(smilesMolList) / noOfFiles)svg = Draw._MolsToGridSVG(smilesMolList[:imagesInOneFile.__index__()], subImgSize=(400, 200), molsPerRow=2)

Also one needs to remember that imagesInOneFile has to be integer.