Python is a versatile language. If you are making use of the Object-oriented (OO) capabilities, you will be happy to learn about magic methods, and how you can leverage them to your advantage. Let’s dive in!
Overriding default logic
Magic methods allow us to override default operator functionality or Class behavior on creation, initialization, and even destruction. A magic method is always prefixed and post-fixed by two underscores
__ . If you’ve used Python for OO programming, you have likely used the magic method
__init__ almost every time!
Let’s explore several magic methods with some practical examples.
__new__() is called by python to create an object before
__init__() is called to initialize the object. Use of
__new__() is not needed in most cases as it can be abused to allow for anti-patterns in development. However,
__new__() is specifically useful — and acknowledged by the official python documentation here — when you need to extend the behaviour of immutable types like tuples. Below is an example.
NumberTuple is a superset of tuple that allows for the specification of string numbers that ought to be converted to tuples. Since tuples are immutable — and
__init__() is called after the tuple is already created — we must use
__new__() to allow for the possibility of classes that extend immutable types. Neat, right?
Printing objects of non-primitive classes are by default not very helpful to the user. They print the class type and memory address.
<__main__.Medium object at 0x7f7f07588c70>
In many cases when you’re building classes, it could be helpful to have an informative output of your object when you explicitly
__str__() expects a string value to be returned. The returned string value will be the value shown on the screen when you attempt to print any object of the
The __repr__() method
You might have noticed that in our discussion of
__str__() above, we asserted that it must be approached with a readability and informative stance. You want to give a good description to the user that will see the console. However, it shouldn’t expose any implementation details; specifically, it shouldn’t have to convey to the reader how the class operates.
But, as developers, we know good debugging is essential to testing and scaling applications. Having output that gets into the details of the implementation can help immensely when chasing a nasty bug. This is where
__repr__ fits in the picture: it stands for
representation and its return value ought to give the developer a solid understanding of the current state of the object. Reusing our
Medium.py example from above, I will add a developer-friendly
__repr__ message that prints the internal id and interests count of the user.
Notice that while
__str__() can easily be invoked through a regular
__repr__() message will only be derived when you invoke the built-in
repr() function (which Python understands as ‘grab the
The __mul__() method
Another category of magic methods is operator overriding: Python allows you to override the primitive operations like
__add__ , respectively. This is especially useful if you are creating mathematical classes that can benefit from the algebraic override. Here is a short example for creating a Dot-Product equipped vector class.
Having the ability to create complex classes that still work with basic operators like
* is a huge syntactic relief for any mathematician that is building complex mathematical models with Python!
That’s it for now. There are many more magic methods that I have not covered here, but I hope this brief introduction to magic methods sparked a curiosity in you to learn more about what Python allows you to override with default behaviour.