Dunder Methods or Magic
Functions
Magic functions (also called "dunder methods") are special predefined
methods in Python classes that start and end with double underscores (
__). They allow you to define how objects of a class behave in various
situations.
Origin of Magic Functions
Magic functions are built into Python's object-oriented programming (OOP)
model. They are inherited from the base object class, which means every class
in Python automatically has access to these methods. When you create a new
class, you're essentially extending the base object class.
How Classes Obtain Magic Functions
python
Copy
# Every class implicitly inherits from object
class MyClass:# This is equivalent to class MyClass(objec
t):
pass
Key Magic Functions (Non-Operator)
1. Initialization and Representation
__init__(self)
Constructor method called when creating an object
Used to initialize object attributes
Dunder Methods or Magic Functions 1
python
Copy
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
__str__(self)
Defines string representation of the object
Called by str() function and print()
python
Copy
def __str__(self):
return f"Student: {self.name}, Age: {self.age}"
__repr__(self)
Provides a detailed string representation
Used for debugging and development
Typically shows how to recreate the object
python
Copy
def __repr__(self):
return f"Student(name='{self.name}', age={self.age})"
2. Comparison Magic Functions
__eq__(self, other)
Defines equality comparison ( == )
Compares object attributes
Dunder Methods or Magic Functions 2
python
Copy
def __eq__(self, other):
if not isinstance(other, Student):
return False
return self.name == other.name and self.age == other.ag
e
__lt__(self, other)
Defines less than comparison ( < )
Useful for sorting objects
python
Copy
def __lt__(self, other):
return self.age < other.age
3. Container and Sequence Magic Functions
__len__(self)
Returns the length of the object
Used with len() function
python
Copy
def __len__(self):
return len(self.attributes)# Example
__getitem__(self, key)
Allows indexing or key-based access
Enables iteration-like behavior
Dunder Methods or Magic Functions 3
python
Copy
def __getitem__(self, index):
return self.data[index]
4. Context Management
__enter__(self) and __exit__(self)
Used for context management with with statement
Manage resource allocation and cleanup
python
Copy
class FileManager:
def __init__(self, filename):
self.filename = filename
def __enter__(self):
self.file = open(self.filename, 'r')
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
self.file.close()
Best Practices
1. Implement magic methods to make your classes more Pythonic
2. Be consistent with expected behavior
3. Handle type checking and edge cases
4. Keep implementations simple and intuitive
Complete Example
Dunder Methods or Magic Functions 4
python
Copy
class Library:
def __init__(self, name):
self.name = name
self.books = []
def __str__(self):
return f"Library: {self.name}"
def __len__(self):
return len(self.books)
def add_book(self, book):
self.books.append(book)
Summary
Magic functions provide special behaviors to classes
They are inherited from the base object class
Implement them to create more powerful and intuitive custom classes
Dunder methods were not a part of programming before Object-Oriented
Programming (OOP). They are specifically a feature of Python's implementation
of OOP, drawing inspiration from earlier object-oriented languages like
Smalltalk and C++.
The concept evolved with Python's development:
Python was created by Guido van Rossum in the late 1980s
Early versions of Python (pre-1.0) did not have comprehensive dunder
methods
With Python 2.0 (released in 2000), the protocol for special methods
became more formalized
Dunder Methods or Magic Functions 5
Python 3.x further refined and expanded these methods
The design philosophy behind dunder methods was to:
1. Allow objects to interact with built-in Python functions and operators
2. Provide a consistent way to customize object behavior
3. Enable more intuitive and flexible object-oriented programming
Key milestone: Python 2.2 introduced the concept of "new-style classes" which
significantly expanded and standardized the use of special methods (dunder
methods).
So while the concept of special methods existed in other OOP languages,
Python's implementation of dunder methods as we know them today is
relatively modern, emerging in the late 1990s and early 2000s.
Python Magic Methods Detailed
Breakdown
Object Creation and Initialization
__new__
Called to create a new instance of a class
Called before __init__
Used for controlling instance creation
python
Copy
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
Dunder Methods or Magic Functions 6
__init__
Initialize object attributes
Called after __new__
python
Copy
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
__del__
Called when object is about to be destroyed
Used for cleanup tasks
python
Copy
class FileHandler:
def __del__(self):
print("Object is being deleted")
self.close_resources()
String Representation
__str__
User-friendly string representation
Called by str() and print()
python
Copy
class Point:
def __str__(self):
return f"Point(x={self.x}, y={self.y})"
__repr__
Dunder Methods or Magic Functions 7
Detailed, unambiguous representation
Used for debugging
python
Copy
class Point:
def __repr__(self):
return f"Point({self.x}, {self.y})"
Comparison Methods
Comparison Magic Methods
__lt__ : Less than <
__le__ : Less than or equal <=
__eq__ : Equal ==
__ne__ : Not equal !=
__gt__ : Greater than >
__ge__ : Greater than or equal >=
python
Copy
class Product:
def __init__(self, price):
self.price = price
def __lt__(self, other):
return self.price < other.price
Container and Iteration Methods
__len__
Returns length of object
Used with len()
Dunder Methods or Magic Functions 8
python
Copy
class CustomList:
def __len__(self):
return len(self.items)
__getitem__
Enables indexing
Used with obj[key]
python
Copy
class CustomDict:
def __getitem__(self, key):
return self.data[key]
__iter__ and __next__
Make object iterable
Used in for loops
python
Copy
class CountDown:
def __iter__(self):
self.n = 5
return self
def __next__(self):
if self.n > 0:
result = self.n
self.n -= 1
return result
raise StopIteration
Dunder Methods or Magic Functions 9
Arithmetic Operator Methods
Basic Arithmetic
__add__ : Addition +
__sub__ : Subtraction
__mul__ : Multiplication
__truediv__ : Division /
python
Copy
class Vector:
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
Reverse Arithmetic Methods
__radd__ : Right-side addition
Used when left operand doesn't support operation
python
Copy
def __radd__(self, other):
return self + other# Fallback implementation
Context Management
__enter__ and __exit__
Used with with statement
Manage resource allocation
python
Copy
class DatabaseConnection:
def __enter__(self):
self.connect()
Dunder Methods or Magic Functions 10
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.close()
Conversion and Utility Methods
Type Conversion
__bool__ : Truthiness evaluation
__int__ : Integer conversion
__float__ : Float conversion
python
Copy
def __bool__(self):
return len(self.data) > 0
Numeric Methods
__abs__ : Absolute value
__round__ : Rounding
__floor__ : Floor value
__ceil__ : Ceiling value
python
Copy
def __abs__(self):
return math.sqrt(self.x**2 + self.y**2)
Advanced Methods
Attribute Handling
__getattr__ : Called for missing attributes
__setattr__ : Attribute setting
Dunder Methods or Magic Functions 11
__delattr__ : Attribute deletion
python
Copy
def __getattr__(self, name):
return f"Attribute {name} not found"
Asynchronous Methods
Async Context and Iteration
__await__ : Make object awaitable
__aiter__ : Async iteration
__anext__ : Next async item
python
Copy
async def __aiter__(self):
# Async iteration implementation
pass
Pickling and Copying
__copy__ and __deepcopy__
Control object copying behavior
python
Copy
def __copy__(self):
return self.__class__(**self.__dict__)
Metaclass and Class Creation Methods
__init_subclass__
Called when class is subclassed
Dunder Methods or Magic Functions 12
python
Copy
def __init_subclass__(cls, **kwargs):
# Custom subclass initialization logic
pass
Special Decorator Methods
__call__
Make object callable like a function
python
Copy
class Multiplier:
def __call__(self, x):
return x * self.factor
Performance and Memory Methods
__slots__
Declare fixed set of attributes
Reduce memory usage
python
Copy
class Point:
__slots__ = ['x', 'y']
Dunder Methods or Magic Functions 13