Quick Answer: __str__()
and __repr__()
are Python’s special methods that control how objects are displayed as strings. __str__()
creates user-friendly output for end users, while __repr__()
creates detailed, developer-focused output that ideally can recreate the object.
Understanding these methods is crucial for any Python developer because they affect how your objects appear in:
Tested on Python 3.8–3.13; behavior unchanged across these versions.
Why This Matters: Poor string representation leads to confusing error messages, unhelpful debugging sessions, and frustrated users. Well-implemented __str__()
and __repr__()
methods make your code more professional, debuggable, and user-friendly.
Before diving deep, here are the essentials:
__str__()
→ Human‑readable output for users (CLI/UI, reports, print()
).__repr__()
→ Developer‑focused, unambiguous output (REPL, tracebacks, debug logs); aim to make it constructor‑like.__str__()
is missing, Python falls back to __repr__()
.__repr__()
for any non‑trivial class; add __str__()
when you need end‑user text.eval()
untrusted repr
; use ast.literal_eval
only for pure literals and prefer explicit constructors for everything else.__str__()
for UI/prompts and __repr__()
for logs/tracebacks; abbreviate large payloads with reprlib
; consider __format__
for stable, LLM‑parsable variants (e.g., f"{obj:csv}"
).Quick Answer: Python automatically calls __str__()
when you use print()
, str()
, or string formatting. It calls __repr__()
when you use repr()
, when objects are displayed in the REPL, or when Python needs an unambiguous representation.
When Python needs to convert an object to a string, it follows this hierarchy:
For str(obj)
or print(obj)
:
obj.__str__()
__str__()
doesn’t exist, falls back to obj.__repr__()
<class 'ClassName'>
representationFor repr(obj)
or REPL display:
obj.__repr__()
__repr__()
doesn’t exist, uses the default <class 'ClassName'>
representation# These trigger __str__()
print(my_object)
str(my_object)
f"Object: {my_object}" # Uses !s conversion
"{0}".format(my_object)
# These trigger __repr__()
repr(my_object)
my_object # In REPL
f"Object: {my_object!r}" # Explicit !r conversion
Note: For details on f-strings, see Python f-strings guide.
__str__()
and __repr__()
MethodsLet’s see these methods in action with real examples that demonstrate their practical differences.
datetime
ClassThe datetime.datetime
class perfectly demonstrates the difference between __str__()
and __repr__()
:
import datetime
# Create a datetime object
mydate = datetime.datetime(2023, 1, 27, 9, 50, 37, 429078)
# Using str() - calls __str__()
print("str() output:", str(mydate))
print("print() output:", mydate)
# Using repr() - calls __repr__()
print("repr() output:", repr(mydate))
print("REPL output:", mydate) # In REPL, this shows repr()
Output:
str() output: 2023-01-27 09:50:37.429078
print() output: 2023-01-27 09:50:37.429078
repr() output: datetime.datetime(2023, 1, 27, 9, 50, 37, 429078)
REPL output: datetime.datetime(2023, 1, 27, 9, 50, 37, 429078)
Note: In the Python REPL, entering
mydate
withoutrepr(mydate)
.
Key Observations:
str()
returns a human-readable date formatrepr()
returns a valid Python expression that can recreate the object__repr__()
to be constructor-like when feasible, but avoid eval()
on untrusted text. Use ast.literal_eval
only for pure literals; for complex objects, prefer explicit constructors.class Product:
def __init__(self, name, price, category):
self.name = name
self.price = price
self.category = category
# Create a product
laptop = Product("MacBook Pro", 1999.99, "Electronics")
print("str() output:", str(laptop))
print("repr() output:", repr(laptop))
Output:
str() output: <__main__.Product object at 0x7f8b8c0d4f40>
repr() output: <__main__.Product object at 0x7f8b8c0d4f40>
Problem: Both return the same unhelpful default representation because neither __str__()
nor __repr__()
is implemented.
class Product:
def __init__(self, name, price, category):
self.name = name
self.price = price
self.category = category
def __str__(self):
return f"{self.name} - ${self.price:.2f} ({self.category})"
def __repr__(self):
return f"Product(name='{self.name}', price={self.price}, category='{self.category}')"
# Create a product
laptop = Product("MacBook Pro", 1999.99, "Electronics")
print("str() output:", str(laptop))
print("repr() output:", repr(laptop))
print("print() output:", laptop)
Output:
str() output: MacBook Pro - $1999.99 (Electronics)
repr() output: Product(name='MacBook Pro', price=1999.99, category='Electronics')
print() output: MacBook Pro - $1999.99 (Electronics)
Key Observations:
str()
provides user-friendly information perfect for displaysrepr()
provides developer-friendly information that can recreate the objectprint()
uses str()
by defaultQuick Answer: Well-implemented __str__()
and __repr__()
methods improve code readability, debugging experience, and user experience. Poor implementations can hurt performance and create confusion.
In real-world applications, these methods also play a crucial role in areas like logging and monitoring, where clear and informative object representations are essential for troubleshooting and auditing.
str()
vs repr()
in PythonThis table highlights their differences side by side (see also Advanced Techniques for details on {!r}, {!a}, and custom format).
Aspect | str(obj) |
repr(obj) |
---|---|---|
Intended Audience | End users, CLI output, user-facing logs | Developers, debugging, diagnostic logs |
Primary Usage | print() , str() , f-strings ({obj!s} ), format() |
repr() , REPL, tracebacks, f-strings ({obj!r} ), debugging tools |
Purpose | Human-readable, friendly, concise | Unambiguous, detailed, ideally reconstructable |
Style Guidance | Hide internals, focus on clarity for users | Include class name and key fields, precise and explicit |
Round-Trip Capable? | Not required | Preferably: valid Python expression to recreate the object |
Fallback Behavior | Falls back to __repr__() if __str__() is missing |
Falls back to default <Class at 0x...> if __repr__() is missing |
REPL/Debugger Default | Not shown by default | Shown by default |
Logging | Use for user-facing logs | Use %r /{!r} for diagnostic logs |
f-string Conversion | {obj!s} |
{obj!r} (and {obj!a} for ASCII-escaped) |
Containers | Uses each element’s repr for string conversion |
Same as str ; elements shown via repr |
Use __str__()
when:
Use __repr__()
when:
Here are some practical contexts and which method to prefer:
__str__()
(user-friendly display for customers or end-users)__repr__()
(default in REPL for developer clarity)__str__()
(clear summaries)__repr__()
(unambiguous, detailed state)__str__()
(human-readable guidance)__repr__()
(precise state, redact secrets as needed)# String with special characters
text = "Hello\nWorld\tTab"
print("str() output:")
print(str(text))
print("\nrepr() output:")
print(repr(text))
Output:
str() output:
Hello
World Tab
repr() output:
'Hello\nWorld\tTab'
Key Observations:
str()
displays the actual formatting (newlines, tabs)repr()
shows the escape sequences (\n
, \t
) for debugging# List containing different object types
items = [1, "hello", 3.14, [1, 2, 3]]
print("str() output:", str(items))
print("repr() output:", repr(items))
Output:
str() output: [1, 'hello', 3.14, [1, 2, 3]]
repr() output: [1, 'hello', 3.14, [1, 2, 3]]
Note: For containers, both str()
and repr()
use repr()
for each element, which is why they look the same here.
Python f-strings support conversion flags !s
, !r
, and !a
which explicitly call the str()
, repr()
, and ascii()
functions on the object, respectively:
class Item:
def __init__(self, name):
self.name = name
def __str__(self):
return f"Item: {self.name}"
def __repr__(self):
return f"Item(name='{self.name}')"
item = Item('Widget')
print(f"str: {item!s}") # Calls str(item)
print(f"repr: {item!r}") # Calls repr(item)
print(f"ascii: {item!a}") # Calls ascii(item)
Output:
str: Item: Widget
repr: Item(name='Widget')
ascii: Item(name='Widget')
__repr__
Python’s dataclasses
module automatically generates a __repr__()
method:
from dataclasses import dataclass
@dataclass
class Product:
name: str
price: float
category: str
p = Product("Laptop", 999.99, "Electronics")
print("repr() output:", repr(p))
print("str() output:", str(p))
Output:
repr() output: Product(name='Laptop', price=999.99, category='Electronics')
str() output: Product(name='Laptop', price=999.99, category='Electronics')
Note: Since no __str__()
is defined, str()
falls back to __repr__()
.
__format__
for Domain-Specific SpecsYou can implement __format__
to support custom formatting codes in f-strings:
class Point:
def __init__(self, x, y):
self.x, self.y = x, y
def __repr__(self):
return f"Point({self.x}, {self.y})"
def __format__(self, spec):
if spec == "csv":
return f"{self.x},{self.y}"
if spec == "poly":
return f"POINT x={self.x} y={self.y}"
return str(self)
p = Point(3, 4)
print(f"{p:csv}") # 3,4
print(f"{p:poly}") # POINT x=3 y=4
The reprlib
module helps abbreviate long or nested outputs to prevent log spam or recursion errors:
import reprlib
large_list = list(range(10000))
print(reprlib.repr(large_list)) # [0, 1, 2, 3, 4, ... 9999]
This is useful in production when objects can grow very large.
When logging, prefer lazy formatting with %r
to avoid unnecessary string conversions:
import logging
logging.basicConfig(level=logging.DEBUG)
logging.debug("Created %r", p) # Calls __repr__ only if needed
This defers formatting until the log message is emitted.
While a reconstructable __repr__()
is helpful, never run eval(repr(obj))
on untrusted input. If your __repr__()
returns Python literals, use ast.literal_eval
. For anything else, rely on explicit constructors or serializers instead.
Here’s a comprehensive example showing how to implement both methods for a real-world scenario:
class Product:
def __init__(self, name, price, category, in_stock=True):
self.name = name
self.price = price
self.category = category
self.in_stock = in_stock
def __str__(self):
"""User-friendly representation for customers"""
status = "In Stock" if self.in_stock else "Out of Stock"
return f"{self.name} - ${self.price:.2f} ({status})"
def __repr__(self):
"""Developer-friendly representation for debugging"""
return f"Product(name='{self.name}', price={self.price}, category='{self.category}', in_stock={self.in_stock})"
# Usage examples
laptop = Product("MacBook Pro", 1999.99, "Electronics", True)
phone = Product("iPhone", 999.99, "Electronics", False)
print("=== User Display ===")
print(laptop) # Uses __str__()
print(phone) # Uses __str__()
print("\n=== Developer Debug ===")
print(repr(laptop)) # Uses __repr__()
print(repr(phone)) # Uses __repr__()
print("\n=== F-string Examples ===")
print(f"Product: {laptop!s}") # Explicit str()
print(f"Debug: {laptop!r}") # Explicit repr()
Output:
=== User Display ===
MacBook Pro - $1999.99 (In Stock)
iPhone - $999.99 (Out of Stock)
=== Developer Debug ===
Product(name='MacBook Pro', price=1999.99, category='Electronics', in_stock=True)
Product(name='iPhone', price=999.99, category='Electronics', in_stock=False)
=== F-string Examples ===
Product: MacBook Pro - $1999.99 (In Stock)
Debug: Product(name='MacBook Pro', price=1999.99, category='Electronics', in_stock=True)
This example demonstrates how to represent a database record with readable and reconstructable string output.
DatabaseRecord
class that stores table name, record ID, and data.__str__()
method provides a simple summary suitable for logs.__repr__()
method outputs detailed reconstruction information for debugging.import datetime
class DatabaseRecord:
def __init__(self, table_name, record_id, data):
self.table_name = table_name
self.record_id = record_id
self.data = data
self.created_at = datetime.datetime.now()
def __str__(self):
"""Simple summary for logs"""
return f"Record {self.record_id} from {self.table_name}"
def __repr__(self):
"""Complete reconstruction info"""
return f"DatabaseRecord(table_name='{self.table_name}', record_id={self.record_id}, data={self.data!r}, created_at=datetime.datetime({self.created_at.year}, {self.created_at.month}, {self.created_at.day}, {self.created_at.hour}, {self.created_at.minute}, {self.created_at.second}, {self.created_at.microsecond}))"
# Usage
record = DatabaseRecord("users", 123, {"name": "John", "email": "john@example.com"})
print("Log entry:", str(record))
print("Debug info:", repr(record))
class Config:
def __init__(self, **kwargs):
self.settings = kwargs
def __str__(self):
"""User-friendly config summary"""
return f"Configuration with {len(self.settings)} settings"
def __repr__(self):
"""Exact reconstruction"""
return f"Config({', '.join(f'{k}={v!r}' for k, v in self.settings.items())})"
# Usage
config = Config(debug=True, port=8080, host="localhost")
print("Config:", str(config))
print("Debug:", repr(config))
Problem: str()
and repr()
return identical output.
Cause: Only __repr__()
is implemented, so str()
falls back to it.
Solution: Implement both methods with different purposes:
class BadExample:
def __repr__(self):
return "BadExample()"
# This will show the same for both str() and repr()
obj = BadExample()
print(str(obj)) # BadExample()
print(repr(obj)) # BadExample()
class GoodExample:
def __str__(self):
return "User-friendly display"
def __repr__(self):
return "GoodExample()"
obj = GoodExample()
print(str(obj)) # User-friendly display
print(repr(obj)) # GoodExample()
__repr__()
Not ReconstructableProblem: repr()
output can’t be used to recreate the object.
Solution: Make __repr__()
return valid Python code:
class BadRepr:
def __repr__(self):
return f"BadRepr with value {self.value}" # Not reconstructable
class GoodRepr:
def __init__(self, value):
self.value = value
def __repr__(self):
return f"GoodRepr({self.value!r})" # Reconstructable
# Test reconstruction
obj = GoodRepr("test")
code = repr(obj) # "GoodRepr('test')" — constructor-like for humans/debuggers
reconstructed = GoodRepr(obj.value) # re-create explicitly from known fields
print(f"Original: {obj}")
print(f"Reconstructed: {reconstructed}")
print(f"Equal: {obj.value == reconstructed.value}")
Security note: Never use eval(repr(obj))
on untrusted text. If (and only if) your __repr__()
returns pure Python literals (lists, dicts, numbers, strings), you may use ast.literal_eval
to parse them; otherwise prefer explicit constructors or safe serializers.
Problem: String methods are called frequently and slow down your application.
Solution: Cache expensive computations and keep methods simple:
class OptimizedClass:
def __init__(self, data):
self.data = data
self._str_cache = None
self._repr_cache = None
def __str__(self):
if self._str_cache is None:
# Expensive computation only once
self._str_cache = f"Processed: {self._expensive_processing()}"
return self._str_cache
def __repr__(self):
if self._repr_cache is None:
self._repr_cache = f"OptimizedClass({self.data!r})"
return self._repr_cache
def _expensive_processing(self):
# Simulate expensive operation
return "".join(str(x) for x in self.data)
__str__()
and __repr__()
Methods in Python__str__()
and __repr__()
__str__()
and __repr__()
in MCP Servers (LLM/Agent Context)When you build AI-facing backends using the Model Context Protocol (MCP) Python SDK, clear string representations supercharge both developer ergonomics and LLM reliability.
__repr__()
yields unambiguous traces, while __str__()
gives human-friendly summaries.__str__()
/ __repr__()
decide how it reads.__repr__()
makes reproducing issues from agent logs straightforward.from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Demo Server")
class CalculatorResult:
def __init__(self, a, b, total):
self.a = a
self.b = b
self.total = total
def __str__(self):
# User-friendly for dashboards / human-readable logs
return f"{self.a} + {self.b} = {self.total}"
def __repr__(self):
# Developer-focused, constructor-like (no secrets)
return f"CalculatorResult(a={self.a}, b={self.b}, total={self.total})"
@mcp.tool()
def add(a: int, b: int) -> CalculatorResult:
"""Add two numbers with human/AI-friendly representation."""
return CalculatorResult(a, b, a + b)
logging.debug("tool result %r", result)
.__repr__()
constructor-like where feasible; never eval()
untrusted text (see security note above).reprlib.repr()
to keep agent logs compact.:csv
, :poly
), implement __format__
so f"{obj:csv}"
is stable and parseable.Learn more: The SDK, examples, and transports (stdio, SSE, Streamable HTTP) are documented at the MCP Python SDK repo.
__str__()
and __repr__()
in Python?A: __str__()
returns a human-readable string for end users, while __repr__()
returns a detailed, developer-friendly string that ideally can recreate the object. __str__()
is used by print()
, str()
, and string formatting, while __repr__()
is used by repr()
, the REPL, and debugging tools.
__str__()
required in every Python class?A: No, __str__()
is not required. If you don’t implement it, Python will fall back to __repr__()
. However, implementing both methods provides better user experience and debugging capabilities.
__repr__()
in a class?A: If __repr__()
is not defined, Python uses the default representation: <class 'ClassName'>
or <class 'ClassName'> object at 0x...
. This provides no useful information about the object’s state.
__str__()
and __repr__()
return the same value?A: Yes, they can return the same value, but it’s generally not recommended. __str__()
should be user-friendly, while __repr__()
should be developer-focused and ideally reconstructable.
__repr__()
instead of __str__()
?A: Use __repr__()
for debugging, logging diagnostic information, working in the REPL, or when you need an unambiguous representation that can recreate the object. Use __str__()
for user-facing displays, reports, and UI output.
__repr__()
of an object in the shell?A: In the Python REPL (interactive shell), objects are displayed using __repr__()
because it provides more detailed, developer-friendly information. This helps developers understand the object’s structure and state during interactive sessions.
__repr__()
reconstructable?A: Make __repr__()
return a string that looks like a valid Python expression to recreate the object. For example: return f"ClassName({self.attr!r})"
instead of return f"ClassName with attr {self.attr}"
.
__str__()
and __repr__()
methods?A: Yes, f-strings are perfectly fine and often preferred for their readability and performance. Just be careful with quotes and escaping when creating reconstructable __repr__()
output.
A: These methods are called frequently, so they should be efficient. Avoid expensive computations in these methods, and consider caching if needed. Simple string formatting is usually fast enough.
A: Both methods follow normal inheritance rules. Child classes can override them, and you can call the parent’s method using super().__str__()
or super().__repr__()
. Be careful to maintain the expected behavior when overriding.
__str__()
and __repr__()
impact MCP/LLM agent reliability?A: In MCP pipelines, tools and resources often surface objects in logs and model-visible text. A concise __str__()
keeps prompts/UI readable, while an unambiguous, constructor-style __repr__()
makes traces reproducible and debugging deterministic. Avoid secrets in __repr__()
, use lazy logging (logging.debug("Created %r", obj)
), abbreviate large payloads with reprlib.repr()
, and if you need a machine-stable shape in prompts, expose __format__
(e.g., f"{obj:csv}"
) or return structured data instead of free text.
Understanding and properly implementing __str__()
and __repr__()
methods is essential for writing professional Python code. These methods control how your objects are displayed to both users and developers, affecting everything from user experience to debugging efficiency.
Key Points to Remember:
__repr__()
for any non-trivial class__str__()
when you need user-friendly output__repr__()
reconstructable when possibleeval
on repr
output — prefer explicit constructors or ast.literal_eval
for pure literals.By following these best practices, you’ll create more maintainable, debuggable, and user-friendly Python applications. The investment in proper string representation methods pays dividends throughout the development lifecycle.
To deepen your understanding of Python’s string representation methods and related concepts:
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
Java and Python Developer for 20+ years, Open Source Enthusiast, Founder of https://www.askpython.com/, https://www.linuxfordevices.com/, and JournalDev.com (acquired by DigitalOcean). Passionate about writing technical articles and sharing knowledge with others. Love Java, Python, Unix and related technologies. Follow my X @PankajWebDev
Building future-ready infrastructure with Linux, Cloud, and DevOps. Full Stack Developer & System Administrator @ DigitalOcean | GitHub Contributor | Passionate about Docker, PostgreSQL, and Open Source | Exploring NLP & AI-TensorFlow | Nailed over 50+ deployments across production environments.
Who is responsible for calling the __repr__() and __str__()
- Shashikant Thakur
Hi Pankaj - I still dont understand the difference between the __str__ and __repr__. From your notes you mentioned Python __repr__() function returns the object representation. It could be any valid python expression such as tuple, dictionary, string etc, whereas __str__() represent string representation of the Object. I tried added an expression (return “{firstName:” + self.fname + “, lastName:” + self.lname + “, age:” + str(self.age) + “}”) in __str__() method and returned it to main function, it didnt throw any error. When both __str__() and __repr__() can return only strings or string expressions i am not sure what exactly is the difference. Any inputs would be helpful
- jagan
Sorry, but this is an awful article. The difference between __repr__ and __str__ is that __repr__ is meant for developers (eg. debugging) and __str__ is used for users. You didn’t explain this simple difference and instead wrote many very or slightly wrong things - You write in the summary “__str__ must return string object whereas __repr__ can return any python expression.” which is wrong! - __repr__ needs to return string as well, as you showed earlier! You use class variables and override them with instance variable, why? thats just not needed and beginners will think it is needed (perhaps you think its necessary?) You call the dunder methods directly (eg `p.__str__()`) instead of using the proper builtins (`str(p)` and `repr(p)`) You use camelCase arguments when the python style is snake_case (underscores) You write there is no fallback for missing __repr__ but you clearly show the fallback (Python shows the type and id in hex). Not having a fallback would be something like raising NotImplementedError. There is a convention (but not really necessary) to have repr return a *string* that looks like the constructor for the object, so one can copy paste the repr outout to get identical copy. eg. a proper example would be: ``` class Person: def __init__(name, age): self.name = name self.age = age def __repr__(self): return f"““Person(name=”{self.name}”, age={self.age})“”" # developer friendly def __str__(self): return f"{self.name} is {self.age} years old" # use friendly ``` I don’t normally bash random people for being wrong, but this article is at the top of the Google search results for repr vs str in python, and a lot of beginners will read this.
- Iftah
and hence as you said using: print(str(p)) print(repr(p)) is better than: print(p.__str__()) print(p.__repr__())
- Bhasha
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.
Full documentation for every DigitalOcean product.
The Wave has everything you need to know about building a business, from raising funding to marketing your product.
Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.
New accounts only. By submitting your email you agree to our Privacy Policy
Scale up as you grow — whether you're running one virtual machine or ten thousand.
Sign up and get $200 in credit for your first 60 days with DigitalOcean.*
*This promotional offer applies to new accounts only.