Reputation: 35473
This is a very contrived example as it's not easy to explain the context in which I have ended up implementing this solution. However, if anyone can answer why this particular peculiarity happens, I'd be grateful.
The example:
class A(dict):
def __init__(self):
self['a'] = 'success'
def __getitem__(self, name):
print 'getitem'
return dict.__getitem__(name)
class B(object):
def __init__(self):
self._a = A()
setattr(self, '__getitem__', self._a.__getitem__)
b = B()
c = b['a']
This outputs:
c = b['a']
TypeError: 'B' object is unsubscriptable
Even though it's a bizarre way of doing this (clearly subclassing would be more logical), why doesn't it find the method I have explicitly set?
If I do this:
dir(b)
I get this:
['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', '__getitem__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__', '_a']
The same issue occurs with other methods such as __iter__
. What is it about explicitly defining this method that works?
Upvotes: 2
Views: 884
Reputation: 749
This is because you can't override special class methods on the fly.
I wasn't able to find a reference about this but is basically because they are class methods and are not allowed to be instance methods.
Upvotes: 1
Reputation: 223062
When you use brackets []
python looks in the class. You must set the method in the class.
Here's your code adapted:
class A(dict):
def __init__(self):
self['a'] = 'success'
def __getitem__(self, name):
print 'getitem!'
return dict.__getitem__(self, name)
class B(object):
def __init__(self):
self._a = A()
B.__getitem__ = self._a.__getitem__
b = B()
c = b['a']
Upvotes: 7