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:
- https://docs.python.org/3/reference/datamodel.html#special-lookup
Comments
Comments powered by Disqus