Unlock Python’s Power: Master Magic Methods for Advanced OOP
This tutorial explains Python’s magic (special) methods—including initialization, string representation, arithmetic, comparison, container protocols, iteration, attribute handling, context management, and callable behavior—showing how each method works with clear code examples to make classes more flexible and powerful.
1. Initialization and Cleanup
Magic methods __init__ and __del__ let you run custom code when an object is created or destroyed.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
person = Person("Alice", 25)
print(person.name) # Alice
print(person.age) # 25
class MyClass:
def __init__(self):
print("Object created")
def __del__(self):
print("Object destroyed")
obj = MyClass()
del obj # triggers __del__2. String Representation
__str__returns a user‑friendly string, while __repr__ returns an official representation useful for debugging.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"Person(name={self.name}, age={self.age})"
def __repr__(self):
return f"Person(name={self.name!r}, age={self.age!r})"
person = Person("Alice", 25)
print(person) # Person(name=Alice, age=25)
print(repr(person)) # Person(name='Alice', age=25)3. Arithmetic Operations
Implement arithmetic by defining __add__, __sub__, and __mul__.
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 __sub__(self, other):
return Vector(self.x - other.x, self.y - other.y)
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
v1 = Vector(1, 2)
v2 = Vector(3, 4)
print((v1 + v2).x, (v1 + v2).y) # 4 6
print((v1 - v2).x, (v1 - v2).y) # -2 -2
print((v1 * 3).x, (v1 * 3).y) # 3 64. Comparison Operations
Define ordering and equality with __eq__ and __lt__.
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
def __lt__(self, other):
return self.age < other.age
p1 = Person("Alice", 25)
p2 = Person("Alice", 25)
print(p1 == p2) # True
p3 = Person("Bob", 30)
print(p1 < p3) # True5. Container Protocols
Make objects behave like containers by implementing __len__, __getitem__, __setitem__, and __delitem__.
class MyList:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
def __getitem__(self, index):
return self.items[index]
def __setitem__(self, index, value):
self.items[index] = value
def __delitem__(self, index):
del self.items[index]
lst = MyList([1,2,3,4])
print(len(lst)) # 4
print(lst[1]) # 2
lst[1] = 5
print(lst.items) # [1,5,3,4]
del lst[1]
print(lst.items) # [1,3,4]6. Iterator Protocol
Implement __iter__ and __next__ to make an object iterable.
class MyList:
def __init__(self, items):
self.items = items
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index >= len(self.items):
raise StopIteration
item = self.items[self.index]
self.index += 1
return item
for i in MyList([1,2,3,4]):
print(i) # 1 2 3 47. Attribute Access
Control dynamic attribute handling with __getattr__, __setattr__, and __delattr__.
class MyClass:
def __getattr__(self, attr):
if attr == 'name':
return 'Default Name'
raise AttributeError(f"Attribute {attr} not found")
def __setattr__(self, attr, value):
if attr == 'age' and value < 0:
raise ValueError('Age cannot be negative')
super().__setattr__(attr, value)
def __delattr__(self, attr):
if attr == 'name':
raise AttributeError("Cannot delete attribute 'name'")
super().__delattr__(attr)
obj = MyClass()
print(obj.name) # Default Name
obj.age = 25
# obj.age = -1 # raises ValueError
obj.name = 'Alice'
# del obj.name # raises AttributeError8. Context Manager
Define __enter__ and __exit__ to use the with statement.
class MyFile:
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
self.file = None
def __enter__(self):
self.file = open(self.filename, self.mode)
return self.file
def __exit__(self, exc_type, exc_value, traceback):
self.file.close()
with MyFile('example.txt', 'w') as f:
f.write('Hello, world!')
# file is automatically closed9. Other Common Magic Methods
Make objects callable with __call__ and support membership tests with __contains__.
class MyCallable:
def __call__(self, x, y):
return x + y
func = MyCallable()
print(func(3, 4)) # 7
class MyList:
def __init__(self, items):
self.items = items
def __contains__(self, item):
return item in self.items
lst = MyList([1,2,3,4])
print(2 in lst) # TrueConclusion
The article covered the most frequently used Python magic methods, demonstrating how they enable custom initialization, representation, arithmetic, comparison, container behavior, iteration, attribute management, context handling, and callable objects, thereby empowering developers to write more expressive and flexible classes.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
