Search code examples
pythonclassindexingwrappermagic-methods

Assigning (instead of defining) a __getitem__ magic method breaks indexing


I have a wrapper class similar to this (strongly simplified) example:

class wrap(object):
    def __init__(self):
        self._data = range(10)

    def __getitem__(self, key):
        return self._data.__getitem__(key)

I can use it like this:

w = wrap()
print w[2] # yields "2"

I thought I could optimize and get rid of one function call by changing to this:

class wrap(object):
    def __init__(self):
        self._data = range(10)
        self.__getitem__ = self._data.__getitem__

However, I receive a

TypeError: 'wrap' object does not support indexing

for the print w[2] line with the latter version.

The direct call to the method, i.e., print w.__getitem__(2), works in both cases...

Why does the assignment version not allow indexing?


EDIT: Regarding the "closed for duplication"

I agree that the linked question has the same answer. It is, however, not at all clear that they are the same question. In particular, someone who does not know the answer here, also does not know that there is an overarching "type of problem" at work. Thus, it won't be clear that they find the answer in a seemingly unrelated question about __call__.


Solution

  • Special methods (essentially anything with two underscores on each end) have to be defined on the class. The internal lookup procedure for special methods completely skips the instance dict. Among other things, this is so if you do

    class Foo(object):
        def __repr__(self):
            return 'Foo()'
    

    the __repr__ method you defined is only used for instances of Foo, and not for repr(Foo).