Can we use magic (dunder) methods on instances instead of types in Python?
No, we can't.
The 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. 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 an example to make this clear by using the repr
function which makes the interpreter to call __repr__
dunder method implicitly, to get the representaion of an object.
class Homer: def __repr__(self): return 'This is Homer Simpson...'
Instantiate the class, and check the repr
method of 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 now:
>>> hmr = Homer() # Not calling out `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 only.
Let's go a bit deep, what if we want to change the repr
of class itself. To do that, as you might have guessed already, we need to change the __repr__
on the metaclass.
Defining 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:
>>> hmr = Homer() # Checking the representation of instance first >>> repr(hmr) 'This is Homer Simpson...' # Checking the representation of the class >>> repr(Homer) 'This is metaclass of Homer class, my name is HomerMeta'
Works as expected.
Hope this helps! I would recommend you to read the official doc as always:
-
Comments
Comments powered by Disqus