When you start diving deeper into Python classes, you’ll likely come across strange-looking method names like __str__
, __repr__
, or __len__
. These are dunder methods (short for “double underscore”), and they power many of Python’s built-in behaviors.
But they also raise some excellent questions:
- Why do we use
__str__()
and not just a method calledstr()
? - Why does
str(obj)
work when we never directly call a method on the object? - Can we do the same with any method?
- What’s the difference between class methods and static methods?
This article brings clarity to all of these with clean examples and explanations.
1. Why Python Uses __str__()
Instead of Just str()
The __str__()
method is part of Python’s data model — a special system that lets you control how your objects interact with the language itself.
If you want to control how your object looks when passed to print()
or str()
, override __str__()
.
Example:
pythonCopyEditclass Book:
def __init__(self, title):
self.title = title
def __str__(self):
return f"Book: {self.title}"
book = Book("Python 101")
print(str(book)) # Output: Book: Python 101
Here, str(book)
calls book.__str__()
internally. But what happens if you try using just str()
as a method?
2. What If You Define a str()
Method?
You can define a method named str()
— but Python won’t use it for str(obj)
.
class Book:
def str(self):
return "This is just a regular method"
book = Book()
print(book.str()) # ✅ OK: manual method call
print(str(book)) # ❌ NOT OK: Python ignores your `str()` method
Why?
Because Python uses __str__()
under the hood — it doesn’t look for a method literally named str
.
3. How str(obj)
Really Works
str(obj)
is a built-in function. Internally, Python translates it like this:
def str(obj):
if hasattr(obj, '__str__'):
return obj.__str__()
else:
return obj.__repr__()
That’s why you can do:
str(obj) # works, calls obj.__str__()
But not:
obj.str() # doesn't connect to str(obj) at all
4. Other Built-in Functions and Their Dunder Methods
Built-in Function | Internally Calls |
---|---|
str(obj) | obj.__str__() |
len(obj) | obj.__len__() |
repr(obj) | obj.__repr__() |
abs(obj) | obj.__abs__() |
iter(obj) | obj.__iter__() |
next(obj) | obj.__next__() |
a + b | a.__add__(b) |
So Python has a special internal system to connect these built-in functions to your custom methods, as long as they follow the __dunder__
format.
5. Can You Call Any Method Without an Object?
Only built-in functions like str()
or len()
can be called on your object like that — because Python is hardwired to look for corresponding __dunder__
methods.
For regular methods, you must use an object:
class Car:
def drive(self):
print("Driving")
Car.drive() # ❌ Error: missing required argument 'self'
Car().drive() # ✅ Works
6. Types of Methods in Python: Instance, Class, Static
When defining methods inside a class, you have three choices — and each behaves differently when called.
Instance Methods (Default)
- Take
self
as the first parameter - Require an instance to call
- Can access both instance and class variables
class Dog:
def bark(self):
print("Woof!")
dog = Dog()
dog.bark() # ✅
Class Methods (@classmethod
)
- Take
cls
(the class) as the first parameter - Can be called on the class
- Useful for factory methods or class-level logic
class Dog:
breed = "Labrador"
@classmethod
def get_breed(cls):
return cls.breed
print(Dog.get_breed()) # ✅ Labrador
Static Methods (@staticmethod
)
- No automatic first argument (
self
orcls
) - Can be called on class or instance
- Acts like a regular function inside the class
class Math:
@staticmethod
def add(a, b):
return a + b
print(Math.add(2, 3)) # ✅ 5
7. Quick Comparison Table
Feature | Instance Method | Class Method | Static Method |
---|---|---|---|
First arg | self | cls | None |
Access instance vars | Yes | No | No |
Access class vars | Yes | Yes | No |
Needs instance? | Yes | No | No |
Use case | Object behavior | Factories, class config | Utility functions |
8. Real-World Example Using All Three
class Circle:
pi = 3.14159
def __init__(self, radius):
self.radius = radius
def area(self):
return Circle.pi * self.radius * self.radius
@classmethod
def from_diameter(cls, diameter):
return cls(diameter / 2)
@staticmethod
def describe():
return "Circles are round."
Usage:
c = Circle.from_diameter(10) # uses class method
print(c.area()) # instance method
print(Circle.describe()) # static method
Conclusion
- Python uses
__str__()
instead ofstr()
to avoid name conflicts and signal internal behavior. str(obj)
works because it’s a built-in function that looks for__str__()
behind the scenes.- Only specific built-in functions like
str()
,len()
, andabs()
do this — your own methods require normal calls. - Class methods (
@classmethod
) are used for class-wide behavior, while static methods (@staticmethod
) are just utility helpers.
Mastering these distinctions not only makes your code cleaner but helps you build classes that behave just like Python’s built-in types.
Leave a Reply