pythonmetaprogramming

Overriding special methods on an instance


Consider the following code:

>>> class A(object):
...     pass
...
>>> def __repr__(self):
...     return "A"
...
>>> from types import MethodType
>>> a = A()
>>> a
<__main__.A object at 0x00AC6990>
>>> repr(a)
'<__main__.A object at 0x00AC6990>'
>>> setattr(a, "__repr__", MethodType(__repr__, a, a.__class__))
>>> a
<__main__.A object at 0x00AC6990>
>>> repr(a)
'<__main__.A object at 0x00AC6990>'
>>>

Notice how repr(a) does not yield the expected result of "A"? I want to know why this is the case and if there is a way to achieve this...

In contrast, the following example works however (Maybe because we're not trying to override a special method?):

>>> class A(object):
...     def foo(self):
...             return "foo"
...
>>> def bar(self):
...     return "bar"
...
>>> from types import MethodType
>>> a = A()
>>> a.foo()
'foo'
>>> setattr(a, "foo", MethodType(bar, a, a.__class__))
>>> a.foo()
'bar'
>>>

Solution

  • Python usually doesn't call the special methods (those with name surrounded by __) on the instance, but only on the class. (Although this is an implementation detail, it's characteristic of CPython, the standard interpreter.) So there's no way to override __repr__() directly on an instance and make it work. Instead, you need to do something like so:

    class A(object):
        def __repr__(self):
            return self._repr()
        def _repr(self):
            return object.__repr__(self)
    

    Now you can override __repr__() on an instance by substituting _repr().