Photo by Hitesh Choudhary on Unsplash
Content by: Andrew Scott – Medium
“Dunder” method name is the common pronunciation for python’s built-in method names that start and end with double underscores. Since “Dunder” is easier to say than “double underscore”, the name stuck. These methods are also sometimes referred to as “Special Methods” or “Magic Methods”. However, the only thing magic or special about these methods is that they allow you to include built-in type behavior in your custom classes.
While we sometimes treat these methods as a special language feature, there’s really nothing special about them. An introductory understanding of how to use dunder methods, and which ones are available can help you create much more intuitive and easy to use classes.
In this post we’ll look at several of the dunder methods used for object creation, representation, and comparison. In later posts we will explore other dunder methods such as emulating containers, emulating numeric types, and more.
If you’ve written any python you’ve almost definitely used at least one dunder method, whether you realized it or not.
__init__ is a method you’ve almost certainly used before. It is the dunder method used to initialize a new object. You may not have been aware of this, but when creating a new instance of an object, the dunder method __new__ is actually called first to create a new instance of your class, then the __init__ method is called to initialize that newly created instance.
A few notes about __init__; if you’re working with a derived class, you’re derived class’ __init__ method must explicitly call the base class’ __init__ method using super.__init__(). You must also never return a non-None value from __init__, as doing so will raise a TypeError.
There are two common, and one less common dunder methods used for representing objects. You’ve undoubtedly called these methods many times, even if you weren’t aware you were using them.
__str__ is the most common of the representational methods. The __str__ method will return an “informal” printable representation of an object and return an str type. The __str__ dunder method is called by str() as well as the built-in format() and print() methods. Meaning, that anytime you use print() you’re also calling the __str__ method on whatever object you’re trying to print. Interestingly enough, if __str__ is not defined for an object, it will default to calling __repr__.
You may be less familiar with __repr__, but it is the second of the common representational special methods and it is used to return the “official” string representation of an object. If an accurate representation of the object cannot be achieved due to object complexity, returning a useful description of the instance is also acceptable. The __repr__ method is called by repr().
__bytes__ computes a byte-string representation of an object and returns an object of type bytes.
The so-called “rich comparison” methods will return a bool type and are used implement the backing methods for comparison operators such as == , != , < , > and more. I won’t go over all of these methods here, since you probably see where this is going, but these are the dunder methods called when you compare objects.
__eq__ is the dunder method used for checking equality between objects. This is pretty self-explanatory for strings and numeric objects, but what about more complex objects? The __eq__ method goes hand in hand with the __hash__ method, which as its name might suggest, takes a hashed collection (set, dict, etc.) and returns an integer. If a class does not define an __eq__ method it should also not define a __hash__ method.
Beware of incomplete implementations of __eq__ and other comparison methods, otherwise you may get unexpected results.
It’s also interesting that you don’t actually need to define the __ne__ in cases where you have already defined __eq__ as python will just assign __ne__ to the inverse of __eq__. The opposite is actually also true, if __eq__ is not defined but __ne__ is, python will assign __eq__ to the inverse of __ne__ — however strongly it’s advised to define both or __eq__ only to reduce confusion.
Hopefully you enjoyed this quick look at some of the common dunder methods.