My question:
It seems that __getattr__
is not called for indexing operations, ie I can't use __getattr__
on a class A
to provide A[...]
. Is there a reason for this? Or a way to get around it so that __getattr__
can provide that functionality without having to explicitly define __getitem__
, __setitem__
, etc on A
?
Minimal Example:
Let's say I define two nearly identical classes, Explicit
and Implicit
. Each creates a little list self._arr
on initiation, and each defines a __getattr__
that just passes all attribute requests to self._arr
. The only difference is that Explicit
also defines __getitem__
(by just passing it on to self._arr
).
# Passes all attribute requests on to a list it contains
class Explicit():
def __init__(self):
self._arr=[1,2,3,4]
def __getattr__(self,attr):
print('called __getattr_')
return getattr(self._arr,attr)
def __getitem__(self,item):
return self._arr[item]
# Same as above but __getitem__ not defined
class Implicit():
def __init__(self):
self._arr=[1,2,3,4]
def __getattr__(self,attr):
print('called __getattr_')
return getattr(self._arr,attr)
This works as expected:
>>> e=Explicit()
>>> print(e.copy())
called __getattr_
[1, 2, 3, 4]
>>> print(hasattr(e,'__getitem__'))
True
>>> print(e[0])
1
But this doesn't:
>>> i=Implicit()
>>> print(i.copy())
called __getattr_
[1, 2, 3, 4]
>>> print(hasattr(i,'__getitem__'))
called __getattr_
True
>>> print(i.__getitem__(0))
called __getattr_
1
>>> print(i[0])
TypeError: 'Implicit' object does not support indexing
Python bypasses
__getattr__
,__getattribute__
, and the instance dict when looking up "special" methods for implementing language mechanics. (For the most part, special methods are ones with two underscores on each side of the name.) If you were expectingi[0]
to invokei.__getitem__(0)
, which would in turn invokei.__getattr__('__getitem__')(0)
, that's why that didn't happen.