Phase: 5. OOP | Estimated time: 2 hours | Milestone Project: No
- Module 047 (Polymorphism)
By the end of this module, you will be able to:
- Differentiate
__str__vs__repr__ - Implement
__eq__and understand its relationship with__hash__ - Implement
__len__,__getitem__, and__contains__ - Use
__call__to make objects callable - Use
__bool__to define truthiness - Make objects work with built-in functions
Dunder methods let your custom objects integrate seamlessly with Python's built-in functions and operators. They're the key to writing objects that feel "Pythonic."
__repr__= unambiguous representation (for developers, ideally recreates the object)__str__= readable representation (for end users)
class Point:
"""A 2D point."""
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
"""Return unambiguous representation."""
return f"Point({self.x}, {self.y})"
def __str__(self):
"""Return readable representation."""
return f"({self.x}, {self.y})"
p = Point(3, 4)
print(repr(p)) # Point(3, 4)
print(str(p)) # (3, 4)
print(p) # (3, 4) — calls str()__eq__ defines equality. Python's default uses identity (is). When you define __eq__, you should also define __hash__ if you want objects usable in sets/dict keys.
class Book:
"""A book with ISBN-based equality."""
def __init__(self, title, isbn):
self.title = title
self.isbn = isbn
def __repr__(self):
return f"Book({self.title!r}, {self.isbn!r})"
def __eq__(self, other):
if not isinstance(other, Book):
return NotImplemented
return self.isbn == other.isbn
def __hash__(self):
return hash(self.isbn)
b1 = Book("Python 101", "123-456")
b2 = Book("Python 101", "123-456")
b3 = Book("Python 201", "789-012")
print(b1 == b2) # True (same ISBN)
print(b1 == b3) # False
print(len({b1, b2, b3})) # 2 (b1 and b2 hash same)Make your objects work with len(), indexing, and in:
class Playlist:
"""A playlist that supports common collection operations."""
def __init__(self, name):
self.name = name
self.songs = []
def add(self, song):
self.songs.append(song)
def __len__(self):
return len(self.songs)
def __getitem__(self, index):
return self.songs[index]
def __contains__(self, song):
return song in self.songs
pl = Playlist("Favorites")
pl.add("Song A")
pl.add("Song B")
print(len(pl)) # 2
print(pl[0]) # Song A
print("Song A" in pl) # TrueMake an instance callable like a function:
class Multiplier:
"""A callable multiplier."""
def __init__(self, factor):
self.factor = factor
def __call__(self, value):
return value * self.factor
double = Multiplier(2)
triple = Multiplier(3)
print(double(5)) # 10
print(triple(5)) # 15Define truthiness for your objects:
class Account:
"""Account with custom truthiness."""
def __init__(self, balance):
self.balance = balance
def __bool__(self):
return self.balance > 0
acc1 = Account(100)
acc2 = Account(0)
print(bool(acc1)) # True
print(bool(acc2)) # False
if acc1:
print("Positive balance!") # runs| Function | Calls | Should return | Used by |
|---|---|---|---|
str() |
__str__ |
Readable | print(), f"{obj}" |
repr() |
__repr__ |
Unambiguous | Debugging, logs, REPL |
__str__ falls back to __repr__ |
- Defining
__eq__without__hash__: Sets mutable objects'__hash__toNone. - Making
__repr__return a string that doesn't recreate the object:repr()should ideally be copy-pasteable. - Forgetting
return NotImplementedin__eq__: Allows Python to try the other side's__eq__. - Thinking
__str__is always needed: If only one is defined,__str__falls back to__repr__.
- Create a
class Timewith hours and minutes. Implement__repr__,__str__,__eq__,__hash__. - Add
__add__to supporttime1 + time2. - Create a
class Deckthat implements__len__,__getitem__,__contains__. - Make a
class Greetercallable with__call__.
__repr__is for developers (unambiguous);__str__is for users (readable).- Define
__eq__and__hash__together for sensible equality and hashing. __len__,__getitem__, and__contains__make objects collection-like.__call__makes instances callable;__bool__defines truthiness.- Dunder methods integrate custom objects with Python's built-in functions.
Continue to Module 049: Abstract Base Classes and Interfaces.