__str__, __repr__, __len__0%

__str__, __repr__, __len__

Beginner12 min readUpdated: Jul 11, 2026
Study Materials

__str__, __repr__, and __len__

In Python, the way objects display themselves to developers and end users—as well as how their size is evaluated—is governed by foundational dunder methods: __repr__, __str__, and __len__. Implementing these methods thoughtfully ensures that your custom data structures integrate seamlessly with logging frameworks, interactive debuggers, formatted strings, and built-in Python functions.


1. __repr__ vs __str__: The Core Distinction

Python provides two distinct string representation mechanisms. While they appear similar on the surface, they serve fundamentally different audiences and purposes.

Output
String Conversion Request
┌──────────────────────┴──────────────────────┐
▼ ▼
str(obj) repr(obj)
or print(obj), f"{obj}" or interactive REPL,
│ f"{obj!r}", logger
│ │
Does __str__ exist? │
┌──────┴──────┐ │
YES NO ▼
│ └─────────► Fallback to ──────► Call __repr__
▼ │
Call __str__ ▼
(Informal / User-facing) (Formal / Unambiguous /
Executable code)

Purpose Comparison

Feature__repr__ (Representation)__str__ (String)
AudienceSoftware engineers, maintainers, debuggersEnd users, reports, UI displays
GoalUnambiguous; ideally valid Python code to recreate the objectReadable, clean, human-friendly presentation
FallbackDefaults to <ClassName object at 0x...> if unhandledFalls back to __repr__ automatically if omitted
Invocationrepr(x), REPL output, interactive debugger, %r, !rstr(x), print(x), f"{x}", format(x)

Practical Rule of Thumb

Always implement __repr__ first. If you only implement __repr__, Python uses it as the default fallback for __str__. If you only implement __str__, the object will still display the unhelpful <ClassName object at 0x...> in lists, dictionaries, tracebacks, and interactive shells.

2. Implementing __repr__ and __str__

Here is an architectural pattern for implementing both methods in a domain entity:

Python
from datetime import datetime
from typing import Optional
 
class UserAccount:
"""Represents a registered user profile in an identity system."""
 
def __init__(self, user_id: int, username: str, email: str, created_at: Optional[datetime] = None) -> None:
self.user_id = user_id
self.username = username
self.email = email
self.created_at = created_at or datetime.now()
 
def __repr__(self) -> str:
"""Formal representation: unambiguous and mirrors constructor call."""
return (
f"{self.__class__.__name__}("
f"user_id={self.user_id!r}, "
f"username={self.username!r}, "
f"email={self.email!r}, "
f"created_at={self.created_at!r})"
)
 
def __str__(self) -> str:
"""Informal representation: human-readable label."""
return f"{self.username} <{self.email}> [ID: {self.user_id}]"
 
# Instantiating the user
user = UserAccount(101, "alovelace", "ada@computing.org")
 
# 1. str() and print() invoke __str__
print("Output of print(user):", user)
print("Output of str(user): ", str(user))
 
# 2. repr() invokes __repr__
print("Output of repr(user): ", repr(user))
 
# 3. Inside collections (lists, dicts), Python always renders __repr__
account_list = [user]
print("Inside list representation:", account_list)
 
# 4. Using the !r conversion flag in formatted f-strings
print(f"User in debug log: {user!r}")

3. The __len__ Protocol and Truthiness

The __len__ method hooks into the built-in len(object) function. It is part of the Sequence Protocol and the Mapping Protocol.

Output
Evaluation of: bool(obj)
Does __bool__ exist?
┌────┴────┐
YES NO
│ └──────► Does __len__ exist?
▼ ┌─────┴─────┐
Call __bool__() YES NO
│ ▼
▼ Default:
len(obj) != 0 True

Strict Requirements for __len__

  1. 1
    Must return a non-negative integer (int >= 0).
  2. 2
    Returning a negative integer raises a ValueError: __len__() should return >= 0.
  3. 3
    Returning a non-integer (such as a float or string) raises a TypeError: 'float' object cannot be interpreted as an integer.
  4. 4
    If a class does not define __bool__, Python evaluates truthiness using __len__(): if len(obj) == 0, the object is evaluated as False; otherwise, it evaluates to True.
Python
class TaskQueue:
"""A prioritized task buffer demonstrating __len__ and truthiness fallback."""
 
def __init__(self) -> None:
self._tasks: list[dict[str, str]] = []
 
def push(self, task_name: str, priority: str = "NORMAL") -> None:
self._tasks.append({"task": task_name, "priority": priority})
 
def pop(self) -> dict[str, str]:
if not self._tasks:
raise IndexError("Queue is empty.")
return self._tasks.pop(0)
 
def __len__(self) -> int:
"""Returns the total number of pending tasks."""
return len(self._tasks)
 
def __repr__(self) -> str:
return f"TaskQueue(count={len(self._tasks)})"
 
# Demonstrating __len__ and implicit truthiness
queue = TaskQueue()
 
print(f"Initial queue length: {len(queue)}")
print(f"Is queue truthy? {bool(queue)}") # False because len(queue) == 0
 
queue.push("Process batch payments", "HIGH")
queue.push("Send invoice emails", "NORMAL")
 
print(f"Populated queue length: {len(queue)}")
print(f"Is queue truthy? {bool(queue)}") # True because len(queue) > 0
 
# Idiomatic conditional check
if queue:
print(f"Dispatching task: {queue.pop()['task']}")

4. Complementary Methods: __format__ and __bytes__

In addition to standard string rendering, Python provides specialized representations:

__format__(self, format_spec: str)

Called by format(obj, spec) or f-string specifiers f"{obj:spec}".

Visual Architecture & Process Flow

How data and code flow step-by-step

Flowchart
Step 1
def __init__
self, amount: float, currency_code: str = "USD"
Step 2
None:

5. Architectural Comparison Summary

MethodBuilt-in CallerType ConstraintPrimary Use Case
__repr__repr(x)Must return strDebugging, inspection, recreating the object
__str__str(x), print(x)Must return strUser-friendly UI / logging strings
__len__len(x)Must return int >= 0Size measurement, truthiness fallback
__format__format(x, spec)Must return strCustom formatting specifications
__bytes__bytes(x)Must return bytesBinary serialization

Multiple Choice Questions

1.

What happens when you execute print(obj) on an instance of a class that defines __repr__ but DOES NOT define __str__? A. Python raises an AttributeError indicating missing __str__. B. Python falls back to executing __repr__. C. Python prints the default memory pointer address. D. Python outputs an empty string.

Answer: B
Explanation:In Python's Data Model, if __str__ is not implemented on a class, calls to str(obj) and print(obj) automatically fall back to invoking __repr__.

2.

Which of the following describes the ideal standard design guideline for __repr__? A. It should return a translated string localized to the user's operating system language. B. It should return an unambiguous string that, whenever feasible, is valid Python code capable of recreating the object. C. It must return a unique memory address integer. D. It should only display private attributes prefixed with double underscores.

Answer: B
Explanation:The canonical Python convention for __repr__ is to be unambiguous and, whenever practical, match the expression that could be passed to eval() or executed in Python code to recreate the object.

3.

When an instance is contained inside a standard Python list, how is each item displayed when the entire list is printed via print([item1, item2])? A. Using item.__str__() B. Using item.__repr__() C. Using item.__format__() D. Using item.__bytes__()

Answer: B
Explanation:Python collection containers (such as lists, tuples, sets, and dictionaries) render their enclosed elements using each element's __repr__ method, not __str__.

4.

What will happen if a custom __len__ method returns a negative integer like -5? A. Python converts it to an absolute value (5). B. Python treats the object as having length 0. C. Python raises a runtime ValueError. D. Python raises an OverflowError.

Answer: C
Explanation:Python strictly enforces that __len__() must return a non-negative integer (>= 0). Returning a negative number triggers a ValueError: __len__() should return >= 0.

5.

If an object does not define a __bool__ method, how does Python determine its boolean truthiness in an if obj: conditional check? A. It always defaults to False. B. It calls __len__(); if the length is 0, it is False, otherwise True. If __len__ is also absent, it defaults to True. C. It calls __repr__() and checks if the resulting string is non-empty. D. It raises a TypeError.

Answer: B
Explanation:In the absence of __bool__, Python checks for __len__. If __len__ is defined, the object is truthy if length is non-zero. If neither method is defined, all instances of user-defined classes are considered truthy (True).

Next Lesson

Operator Overloading

Continue learning with hands-on practice, examples, and exercises in the upcoming topic.

Related Lessons

Practice Quiz

Test your understanding of this lesson with 5 questions. Each question has one correct answer.

PrevNext