Mastering __str__() and Method Types in Python: How Built-ins Work and When to Use What

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 called str()?
  • 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 FunctionInternally 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 + ba.__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 or cls)
  • 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

FeatureInstance MethodClass MethodStatic Method
First argselfclsNone
Access instance varsYesNoNo
Access class varsYesYesNo
Needs instance?YesNoNo
Use caseObject behaviorFactories, class configUtility 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 of str() 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(), and abs() 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.

[eatblvd_order_menu]

Leave a Reply

Your email address will not be published. Required fields are marked *