Dunder Methods - breaking it down.
Learning to code can be many things, rewarding, exciting, challenging, and often frustrating and confusing. As I continue my journey as a developer, I have often encountered situations where what I had intended to be a brief internet search, quickly became a rabbit hole of information that while undoubtedly important and even useful information was wildly out of the scope of both the work I was doing and my knowledge. Often leaving me more confused with my question only partially answered.
One concept that initially had me confused was the idea of Dunder methods. IIn this blog post, I aim to provide a beginner's guide that offers a brief and informative introduction to Dunder methods. The goal is to give those who are still at the beginning of their Python journey a solid foundation in the basics
Who, What, When, Where, Why and How
what is a Dunder Method? And when and where do we use them?
Dunder or "double underscore" methods are special types of methods named for the two underscores before and after their name. They are also known as "magic methods" or "special methods" for a good reason – they allow for the customization of Python classes, enabling developers to define how class instances react to various circumstances and operations. Dunder methods are primarily used when working with classes and data structures, making them an integral part of Python's key concept: Object Oriented Programming (OOP).
who, how and why: get to know some common Dunder Methods.
Python contains a great many Dunder methods, and all of them are extremely useful. In this post, I will explain several of the most widely and commonly used Dunder methods. A more comprehensive list of Dunder methods can be found: here
Meet: __init__
, __str__
, __repr__
, and __len__
When the
__init__
method is used, it allows for a class instance to be initialized with specific attributes. Reminder theself
passed as a parameter to each method refers to an individual instance of the class.The
__str__
and__repr__
methods are both used in the representation of various aspects of objects as a string. By defining these methods we can control the way objects are printed or converted into strings.__str__
provides a more "human-friendly" representation designed for ease of readability.__repr__
on the other hand is designed to provide a concise and unambiguous representation of the objectIn other words
__str__
prints end-user output and__repr__
prints information useful for debugging
The
__len__
method allows for objects to have their length defined. In OOP, this is extremely useful as it can allow for the customization and creation of precise container objects such as lists or dictionaries.
class Person:
def __init__(self, name):
self.name = name
self.items = []
def __str__(self):
return f"Person: {self.name}"
def __repr__(self):
return f"Person(name='{self.name}')"
def __len__(self):
return len(self.items)
-------------------------------------------------------------------------------
person = Person("Alice")
my_list = MyList()
my_list.items = [1, 2, 3, 4]
print(person.name) # Output: Alice
print(str(person)) # Output: Person: Alice
print(repr(person)) # Output: Person(name='Alice')
print(len(my_list)) # Output: 4
MEET: __iter__
and __next__
These two methods are used in conjunction and allow for an object to be iterated using different types of loops.
__iter__
returns an 'iterator' for the object(self.current in the code below) allowing for the__next__
method to decide if and how the next item in the iteration can be retrieved.
class MyIterable:
def __init__(self):
self.items = []
def __iter__(self):
self.current = 0
return self
def __next__(self):
if self.current >= len(self.items):
#stop iteration is a terminating condition that helps
#prevent infinite iteration
raise StopIteration
item = self.items[self.current]
self.current += 1
return item
my_iterable = MyIterable()
my_iterable.items = [1, 2, 3, 4]
for item in my_iterable:
print(item) # Output: 1 2 3 4
One more note about underscores:
There is one more topic it is important to take note of when learning about Dunder methods, and that is just what exactly is going on when you see underscores popping up in your code. The following are several important rules regarding underscores it is important to keep in mind
Single Leading Underscore [
_username
]:A single leading underscore conventionally indicates privacy.
It serves as a hint to other developers that the attribute or method is intended for internal use within the class or module.
Single Trailing Underscore
A single trailing underscore is used to avoid naming conflicts.
It differentiates variable names from Python keywords.
def method(name, class='Classname'): #will return a syntax error ... def method(name, class_='Classname'): #will work just fine
Double Trailing Underscore
Double-leading underscores trigger name mangling, preventing accidental overriding of attributes in subclasses.
The attribute name gets prefixed with a single underscore and the class name.
Conclusion:
Congratulations on making it to the end of my introduction to Dunder methods, integral parts of creating and customizing sleek, elegant and flexible code. I hope that by reading what I have to say you were able to gain a more solid and concrete foundation on which to build your knowledge of Dunder methods, Python and coding in general.
References:
Python Documentation: Dunder Methods, Basic Object Customization
Real Python: Dunder Method Basics
Geeks For Geeks: Dunder Methods In Python