Skip to main content

Python : Can we use magic/dunder methods as instance attributes directly instead of putting them in type definition?

No, we can't.

The magic/dunder methods are looked up implicitly on the type definition while special functions, keywords, or operators are to be resolved by the runtime. They don't follow the regular attribute lookup procedure i.e. doesn't follow the __getattribute__ chain. This makes them fast to access as the runtime only needs to search on the type, not on instance dict.

So, what about classes themselves? What dunder methods should be used when any special function is called on them?

As any class is an instance of a metaclass, the dunder methods defined on the metaclass would be used.

Let's see a few examples to get a clear overview of all these. We'll be using the repr function, for which the interpreter will call __repr__ dunder method implicitly, in order to get the representation of an object.

Defining class Homer with __repr__ method:

class Homer:
    def __repr__(self):
        return 'This is Homer Simpson...'

Instantiate the class, and invoke the repr method on the instance:

>>> hmr = Homer()

>>> repr(hmr)
'This is Homer Simpson...'

Expectedly, the __repr__ on the body of Homer class is being called. Now, what if we try to attach the __repr__ as an attribute of the instance directly:

class Homer(metaclass=HomerMeta):
    def __init__(self):
        self.__repr__ = lambda: 'This is Homer Simpson...'

Let's check how it goes:

>>> hmr = Homer()

# `repr` does not call our `self.__repr__`
>>> repr(hmr)
'<__main__.Homer object at 0x7f3b018d2a20>'

# Explicit call
>>> hmr.__repr__()
'This is Homer Simpson...'

As we can see the __repr__ function defined in the class body is invoked when calling repr.

Let's go a bit deeper; what if we want to change the repr of class itself. To do that (as you might have guessed already), we need to define __repr__ on the metaclass.

Defining the metaclass first:

class HomerMeta(type):
    def __repr__(cls):
        return f'This is metaclass of {cls.__name__} class, my name is {cls.__class__.__name__}'

Now, defining class with metaclass HomerMeta:

class Homer(metaclass=HomerMeta):
    def __repr__(self):
        return 'This is Homer Simpson...'

Let's check it out:

# Check the representation of the class
>>> repr(Homer)
'This is metaclass of Homer class, my name is HomerMeta'

# Check the representation of instance as well
>>> hmr = Homer()

>>> repr(hmr)
'This is Homer Simpson...'

Works as expected.

Hope this helps! I would recommend you to check out the official doc as always:



Comments powered by Disqus