Understanding Python Dunder Methods
05 Sep 2024Dunder methods (short for “double underscore methods”) are special methods in Python that have double underscores (__) before and after their names. They define how objects of a class behave when used with built-in operations such as print(), indexing, comparisons, or mathematical operations. Here’s a breakdown of some common dunder methods and how you can use them to customize your Python objects.
1. __init__ – The Constructor
The __init__ method is the constructor of a class and is called when you create a new instance. This is where you can initialize attributes for the object.
class Person:
def __init__(self, name):
self.name = name
p = Person("Sarah")
print(p.name) # Outputs: Sarah
Explanation: In this example, we define a Person class with a constructor that takes a name as an argument. When an instance of the Person class is created, the __init__ method is called to initialize the name attribute.
2. __str__ – String Representation for Humans
The __str__ method controls how an object is printed or represented as a string using print() or str().
class Person:
def __init__(self, name):
self.name = name
def __str__(self):
return f"Person: {self.name}"
p = Person("Sarah")
print(p) # Outputs: Person: Sarah
Explanation: Here, the __str__ method provides a human-readable representation of the object. When you print the object, it displays "Person: Sarah" instead of the default representation like <Person object at 0x...>.
3. __repr__ – String Representation for Developers
The __repr__ method is like __str__ but is meant to provide a detailed, unambiguous string that can be used for debugging.
class Person:
def __init__(self, name):
self.name = name
def __repr__(self):
return f"Person({self.name!r})"
p = Person("Sarah")
print(repr(p)) # Outputs: Person('Sarah')
Explanation: The __repr__ method provides a string that shows exactly how to recreate the object, making it helpful for debugging.
4. __len__ – Define Object Length
If you want to define a length for your object, implement the __len__ method, which is used by the len() function.
class Group:
def __init__(self, members):
self.members = members
def __len__(self):
return len(self.members)
g = Group(["Sarah", "John", "Alice"])
print(len(g)) # Outputs: 3
Explanation: The __len__ method returns the length of the group, which is the number of members. Here, len(g) gives us 3.
5. __getitem__ – Access Items with Indexing
The __getitem__ method allows your object to be indexed like a list or dictionary.
class Group:
def __init__(self, members):
self.members = members
def __getitem__(self, index):
return self.members[index]
g = Group(["Sarah", "John", "Alice"])
print(g[1]) # Outputs: John
Explanation: The __getitem__ method defines how the object should behave when accessed with square brackets (e.g., g[1]).
6. __setitem__ – Set Items with Indexing
The __setitem__ method defines how an object’s item can be updated via indexing.
class Group:
def __init__(self):
self.members = {}
def __setitem__(self, key, value):
self.members[key] = value
g = Group()
g[0] = "Sarah"
print(g.members) # Outputs: {0: 'Sarah'}
Explanation: Here, we can assign values to g using indexing, and the __setitem__ method updates the members dictionary.
7. __delitem__ – Delete Items with Indexing
The __delitem__ method allows you to delete an item from the object using del.
class Group:
def __init__(self, members):
self.members = members
def __delitem__(self, index):
del self.members[index]
g = Group(["Sarah", "John", "Alice"])
del g[1]
print(g.members) # Outputs: ['Sarah', 'Alice']
Explanation: The __delitem__ method is called when you delete an item from the object using del.
8. __call__ – Make Objects Callable
If you want an object to behave like a function, implement the __call__ method.
class Greet:
def __call__(self, name):
return f"Hello, {name}!"
greet = Greet()
print(greet("Sarah")) # Outputs: Hello, Sarah!
Explanation: Here, the Greet object can be called like a function because of the __call__ method.
9. __eq__ – Equality Comparison
The __eq__ method defines how two objects should be compared for equality using ==.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
return self.x == other.x and self.y == other.y
p1 = Point(1, 2)
p2 = Point(1, 2)
print(p1 == p2) # Outputs: True
Explanation: The __eq__ method compares two Point objects for equality by checking their x and y values.
10. __lt__ – Less Than Comparison
The __lt__ method allows you to define how one object should be compared to another using the less-than operator (<).
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __lt__(self, other):
return (self.x + self.y) < (other.x + other.y)
p1 = Point(1, 2)
p2 = Point(2, 3)
print(p1 < p2) # Outputs: True
Explanation: The __lt__ method compares two Point objects by their combined x and y values.
11. __add__ – Define Addition Behavior
The __add__ method allows you to define how objects should behave when added with the + operator.
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __repr__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2) # Outputs: Vector(4, 6)
Explanation: The __add__ method enables the addition of two Vector objects by adding their x and y values together.
12. __enter__ and __exit__ – Context Managers
These methods define the behavior of an object when used in a with statement, allowing for setup and teardown logic.
class File:
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
def __enter__(self):
self.file = open(self.filename, self.mode)
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
self.file.close()
with File("example.txt", "w") as f:
f.write("Hello, World!")
Explanation: The __enter__ method opens the file, and the __exit__ method ensures the file is closed, even if an error occurs.
13. __contains__ – Define in Keyword Behavior
The __contains__ method defines how the in keyword works for your object.
class Group:
def __init__(self, members):
self.members = members
def __contains__(self, item):
return item in self.members
g = Group(["Sarah", "John", "Alice"])
print("John" in g) # Outputs: True
Explanation: The __contains__ method allows you to check if an item is in the Group using the in keyword.
14. __iter__ – Make Objects Iterable
The __iter__ method makes your object iterable so it can be used in a for loop.
class Group:
def __init__(self, members):
self.members = members
def __iter__(self):
return iter(self.members)
g = Group(["Sarah", "John", "Alice"])
for member in g:
print(member)
# Outputs: Sarah, John, Alice
Explanation: The __iter__ method allows the Group object to be used in a loop to iterate over its members.
These are just some of the many dunder methods available in Python. They give you a lot of control over how objects behave and interact with Python’s built-in functionality, making your code more flexible and powerful. You can execute all the code in this google colab notebook.