Goal
You’ll be able to use common special methods (dunder methods) to make your own classes work naturally with Python’s built-in functions and operators, and understand why print()ing an object without one shows something unhelpful by default.
Learn
Special methods (also called “dunder” methods, for “double underscore”) let your own classes hook into Python’s built-in behavior — how an object prints, compares, or responds to built-in functions like len().
By default, printing a plain object shows something genuinely unhelpful:
class Book:
def __init__(self, title):
self.title = title
b = Book("1984")
print(b) # <__main__.Book object at 0x7f8a1c0d5f10> — not useful at all Defining __str__ controls what print() actually shows:
class Book:
def __init__(self, title):
self.title = title
def __str__(self):
return f"Book: {self.title}"
b = Book("1984")
print(b) # "Book: 1984" — genuinely useful now Other common special methods: __len__ lets len(my_object) work correctly, __eq__ defines what == means for your objects (by default, two separate objects are never considered equal, even with identical data, unless you define this), and __add__ lets your objects work with the + operator.
The genuinely important mindset: dunder methods aren’t obscure syntax tricks — they’re the mechanism that lets your own custom classes integrate naturally with Python’s built-in language features, rather than requiring special custom function calls instead of normal, expected syntax.
Decision Task
You create two separate Book objects with identical titles, and check book1 == book2. Before reading on: does this return True or False by default, without defining __eq__ yourself?
Show Answer
False, by default — even with completely identical attribute data, two separate objects are never automatically considered equal unless you explicitly define __eq__ yourself. By default, == checks whether they’re literally the exact same object in memory, not whether their data happens to match, which is why defining __eq__ is necessary if you want meaningful data-based equality comparison for your own classes.
Common Mistake
Assuming Python automatically provides sensible print(), ==, or len() behavior for custom classes without defining the corresponding dunder methods yourself. Without __str__, printing shows an unhelpful memory address; without __eq__, == only checks identity, not data equality — these behaviors need to be explicitly defined, they don’t happen automatically just because a class “seems like” it should support them.
Practice Questions
1. Write a __str__ method for a class Point with x and y attributes, returning something like “(3, 5)”.
Show Answer
def __str__(self):\n return f"({self.x}, {self.y})"
2. What does print() show for a custom object with no __str__ method defined?
Show Answer
An unhelpful default representation including the class name and a memory address, like <__main__.Book object at 0x…>.
3. What special method would you define to make len(my_object) work correctly for a custom class?
Show Answer
__len__
4. True or False: by default, two separate objects with identical attribute data are automatically considered equal with ==.
Show Answer
False — by default, == checks object identity (are they literally the same object), not data equality, unless __eq__ is explicitly defined.
5. What does “dunder” refer to in “dunder methods”?
Show Answer
“Double underscore” — referring to the __ prefix and suffix these special method names use, like __init__ or __str__.
Try It Yourself
Without looking back, add an __eq__ method to a class Point (with x and y attributes) that returns True if two Point objects have the same x and y values.
Show Answer
def __eq__(self, other):\n return self.x == other.x and self.y == other.y — comparing the actual attribute values of both objects, rather than relying on default identity comparison.
Quick Check
1. What are special/dunder methods used for?
Show Answer
Letting custom classes hook into Python’s built-in behavior, like printing, comparison, or built-in functions.
2. What does __str__ control?
Show Answer
What print() (and str()) actually displays for an object.
3. What’s the default == behavior for two objects if __eq__ isn’t defined?
Show Answer
It checks object identity (are they literally the same object), not data equality.
4. What does “dunder” stand for?
Show Answer
“Double underscore,” referring to the __ prefix/suffix pattern.
5. What does defining __len__ let you do?
Show Answer
Use the built-in len() function directly on your custom object.