What are these __method__ in š you sssssay? Look no further!
Hamzza K
Posted on September 20, 2023
Have you ever used or seen the __init__()
or __str__()
method in Python classes? These are called dunder methods! Dunder, short for "double underscore", is a term used in Python to refer to special methods that allow programmers to modify the behavior of objects in a logical and intuitive way. In this article, we will examine Python's dunder methods and show how to use them to create more Pythonic code. We'll cover the basics of dunder methods, their common use cases, and best practices for using them effectively.
How do Dunder Methods work?
Dunder (double underscore) methods, are unique in the Python programming language that have double underscores defined on either side of their names, such as __init__()
, __str__()
, or __eq__()
. These methods allow you to modify the behaviour of objects and give a more user-friendly interface for dealing with them. You can specify how instances of the class should act when they are generated, printed, compared, or utilised in arithmetic operations by specifying dunder methods in a class declaration.
Common Use Cases for Dunder Methods
Dunder methods are extensively used in Python libraries and frameworks, and have become a standard convention in the Python community. Here are some common use cases for dunder methods:
Initialization
TheĀ __init__()
Ā method is used to initialize a new instance of a class. It is called when a new object is created, and is used to set the initial state of the object. This method takes aĀ self
Ā parameter, which refers to the instance of the class being initialized, and any additional parameters that are needed to set theĀ initial stateĀ of the object. TheĀ __init__
method is most commonly used to initialize the attributes of an object when it is created.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
person = Person("John", 25)
print(person.name) # Output: Alice
print(person.age) # Output: 25
String Representation
TheĀ __str__()
andĀ __repr__()
methods serve the purpose of defining a string representation of an object.
WhileĀ
__str__()
is used to define a human-readable string representation,Ā__repr__()
is used to define a machine-readable format for the object.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"{self.name} ({self.age} years old)"
person = Person("John", 25)
print(person) # Output: John (25 years old)
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f"Person(name='{self.name}', age={self.age})"
person = Person("John", 25)
print(person) # Output: Person(name='John', age=25)
The
__init__
method can be used in scenarios involving multiple inheritance to initialize attributes of all parent classes.
class Animal:
def __init__(self, species):
self.species = species
def speak(self):
pass
class Mammal:
def __init__(self, mammal_type):
self.mammal_type = mammal_type
def feed_young(self):
pass
class Dog(Animal, Mammal):
def __init__(self, name, age):
Animal.__init__(self, "Dog")
Mammal.__init__(self, "Canine")
self.name = name
self.age = age
def speak(self):
return "Woof"
dog = Dog("Fido", 3)
print(dog.species) # Output: Dog
print(dog.mammal_type) # Output: Canine
print(dog.name) # Output: Fido
print(dog.age) # Output: 3
print(dog.speak()) # Output: Woof
Container Operations
Dunder methods can be used to define the behavior of container operations such asĀ len()
, indexing ([]
), assignment to anĀ indexed value (obj[index] = value
), deletion of an indexed value (del obj[index]
), andĀ membership testing (in
)
-
__len__()
TheĀ
__len__()
method is used to define the behavior of theĀlen()
function for objects of a class. It should return the number of items in the container.
class MyList:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
my_list = MyList([1, 2, 3])
print(len(my_list)) # Output: 3
__getitem__()
TheĀ __getitem__()
Ā method is used to define the behavior of indexing ([]
) for objects of a class. It should return the item at the given index.
class MyList:
def __init__(self, items):
self.items = items
def __getitem__(self, index):
return self.items[index]
my_list = MyList([1, 2, 3])
print(my_list[2]) # Output: 3
__setitem__()
TheĀ __setitem__()
Ā method is used to define the behavior of assignment to anĀ indexed valueĀ (obj[index] = value
) for objects of a class. It should set the item at the given index to the given value.
class MyList:
def __init__(self, items):
self.items = items
def __setitem__(self, index, value):
self.items[index] = value
my_list = MyList([1, 2, 3, 4, 5])
my_list[2] = 66
print(my_list.items) # Output: [1, 2, 66, 4, 5]
__delitem__()
TheĀ __delitem__()
Ā method is used to define the behavior of deletion of an indexed value (del obj[index]
) for objects of a class. It should delete the item at the given index.
class MyList:
def __init__(self, items):
self.items = items
def __delitem__(self, index):
del self.items[index]
my_list = MyList([1, 2, 3, 4, 5])
del my_list[2]
print(my_list.items) # Output: [1, 2, 4, 5]
__contains__()
- TheĀ
__contains__()
Ā method is used to define the behavior ofĀ membership testingĀ (in
) for objects of a class. It should returnĀTrue
Ā if the given value is present in the container, andĀFalse
Ā otherwise.
class MyList:
def __init__(self, items):
self.items = items
def __contains__(self, value):
return value in self.items
my_list = MyList([1, 2, 3, 4, 5])
print(2 in my_list) # Output: True
print(10 in my_list) # Output: False
These examples demonstrate how container operations can customize the behavior of Python objects. By defining these methods in a class definition, you can provide a more intuitive interface for interacting with objects and make your code more flexible and customizable.
Comparison
Dunder methods can be used to define the behavior ofĀ comparison operatorsĀ such asĀ ==
,Ā <
,Ā >
,Ā <=
, andĀ >=
Ā for objects of a class. These methods should returnĀ True
Ā orĀ False
Ā depending on whether the comparison is true or false.
__eq__()
TheĀ __eq__()
Ā method is used to compare two objects for equality.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
return self.name == other.name and self.age == other.age
person1 = Person("Alice", 25)
person2 = Person("Bob", 30)
person3 = Person("Alice", 25)
print(person1 == person2) # Output: False
print(person1 == person3) # Output: True
__lt__()
TheĀ __lt__()
Ā method is used to compare two objects to check if one is less than the other.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __lt__(self, other):
return self.age < other.age
person1 = Person("Alice", 25)
person2 = Person("Bob", 30)
print(person1 < person2) # Output: True
print(person2 < person1) # Output: False
__gt__()
TheĀ __gt__()
Ā method is used to compare two objects to check if one is greater than the other.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __gt__(self, other):
return self.age > other.age
person1 = Person("Alice", 25)
person2 = Person("Bob", 30)
print(person1 > person2) # Output: False
print(person2 > person1) # Output: True
__le__()
TheĀ __le__()
Ā method is used to compare two objects to check if one is less than or equal to the other. Here's an example:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __le__(self, other):
return self.age <= other.age
person1 = Person("Alice", 25)
person2 = Person("Bob", 30)
person3 = Person("Charlie", 25)
print(person1 <= person2) # Output: True
print(person2 <= person1) # Output: False
print(person1 <= person3) # Output: True
__ge__()
TheĀ __ge__()
Ā method is used to compare two objects to check if one is greater than or equal to the other. Here's an example:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __ge__(self, other):
return self.age >= other.age
person1 = Person("Alice", 25)
person2 = Person("Bob", 30)
person3 = Person("Charlie", 25)
print(person1 >= person2) # Output: False
print(person2 >= person1) # Output: True
print(person1 >= person3) # Output: True
Arithmetic Operations
Dunder methods can be used to define the behavior ofĀ arithmetic operatorsĀ such asĀ +
,Ā -
,Ā *
, andĀ /
Ā for objects of a class. These methods should return a new object that represents the result of theĀ arithmetic operation.
__add__()
TheĀ __add__()
Ā method is used to define the behavior of theĀ +
Ā operator when applied to two objects. Here's an example:
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)
v1 = Vector(1, 2)
v2 = Vector(3, 4)
v3 = v1 + v2
print(v3.x) # Output: 4
print(v3.y) # Output: 6
__sub__()
TheĀ __sub__()
Ā method is used to define the behavior of theĀ -
Ā operator when applied to two objects. Here's an example:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __sub__(self, other):
return Vector(self.x - other.x, self.y - other.y)
v1 = Vector(1, 2)
v2 = Vector(3, 4)
v3 = v2 - v1
print(v3.x) # Output: 2
print(v3.y) # Output: 2
__mul__()
TheĀ __mul__()
Ā method is used to define the behavior of theĀ *
Ā operator when applied to two objects. Here's an example:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __mul__(self, other):
return Vector(self.x * other, self.y * other)
v1 = Vector(1, 2)
v2 = v1 * 3
print(v2.x) # Output: 3
print(v2.y) # Output: 6
__truediv__()
TheĀ __truediv__()
Ā method is used to define the behavior of theĀ /
Ā operator when applied to two objects. Here's an example:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __truediv__(self, other):
return Vector(self.x / other, self.y / other)
v1 = Vector(3, 6)
v2 = v1 / 3
print(v2.x) # Output: 1.0
print(v2.y) # Output: 2.0
Best Practices for Using Dunder Methods
While dunder methods can be a powerful tool for customizing the behavior of objects in Python, it is important to use them thoughtfully and appropriately. Here are some best practices for using dunder methods effectively:
- Use dunder methods to define object behavior in a way that is consistent with Python conventions and libraries.
- Use descriptive names for dunder methods that accurately reflect their purpose and behavior.
- Be aware of the specific names and behaviors of dunder methods used by Python itself, and use them appropriately when defining your own dunder methods.
- Use dunder methods judiciously. Too many can make your code more complex and harder to understand.
- Thoroughly test your dunder methods to ensure that they behave as expected and do not introduce unexpected side effects.
Conclusion
Dunder methods are a powerful feature of Python that enables developers to customize the behavior of objects in a consistent and intuitive way. By using dunder methods effectively, you can make your code more readable, maintainable, and flexible. You can also ensure that it is consistent with the expectations of other Python developers. Understanding the usage of dunder methods is an important part of writing Pythonic code, and can help you become a more effective Python developer.
Posted on September 20, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 19, 2024