Here is a very simple class to demonstrate the theory:
class Indexable(object):
def __getitem__(self, index):
print("You indexed me with {}.".format(index))
In use, then:
>>> i = Indexable()
>>> i[12]
You indexed me with 12.
Here we can clearly see that i[12]
resolves to Indexable.__getitem__(i, 12)
.
This happens everywhere - even if you call self[avariable]
inside an instance method (including __getitem__
), you will end up calling Indexable.__getitem__(self, avariable)
. This explains the infinite loop if you include self[avariable]
inside Indexable.__getitem__
.
This will always be the case in Python, you cannot redefine this syntax without rewriting it yourself. This is a "magic method", just like str(instance)
calls Class.__str__(instance)
.
In practice, you will generally want to define some useful behaviour for indexing, perhaps you want to fake numpy
-style comma-separated indexing:
class NotArray(object):
def __init__(self, data):
self.data = data
def __getitem__(self, index):
data = self.data
for ind in index:
data = data[ind]
return data
This can be used like:
>>> arr = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
>>> arr[1, 1, 1]
Traceback (most recent call last):
File "<pyshell#51>", line 1, in <module>
arr[1, 1, 1]
TypeError: list indices must be integers, not tuple
>>> arr = NotArray([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
>>> arr[1, 1, 1]
8
Note that we have now defined a source for the data to be returned for a given index.
You could also use this to implement non-standard syntax, like I do in my answer to this question: is it possible to add some new syntax in javascript? But this is generally discouraged, as it will confuse readers of your code.