Decoding Python Magic -> __str__ , __repr__ and __format__

Let’s master object representation.

Rahul Beniwal
Level Up Coding

--

Greetings Everyone,

Today, in the next installment of the “Decoding Python Magic” series, we will delve into the magic methods __str__, __repr__, and __format__. If you haven't already, feel free to check out our previous discussions on important magic methods, including the Descriptor Protocol, for a comprehensive understanding of Python's powerful capabilities.

__str__ and __repr__ are indeed commonly used magic methods in Python, with __format__ being less commonly known but equally important.

Image Credit Unsplash

__str__

The __str__ method is a special method in Python that defines how an object should be represented as a string when using the str() function or when the object is used in string formatting with the f-string syntax.

It’s meant to provide a readable, user-friendly representation of the object.

class Person:
def __init__(self, name, age):
self.name = name
self.age = age

def __str__(self):
return f"{self.name} - {self.age}"

p = Person("Alice", 30)
print(p) # Alice - 30
print(f'Person: {p}') # Person: Alice - 30

How to see SQL query prepared by Django ORM ?

In [5]: authors = Author.objects.filter(name="Test Author")

In [6]: print(authors.query)
SELECT "core_author"."id", "core_author"."name", "core_author"."last_name" FROM "core_author" WHERE "core_author"."name" = Test Author

__str__ method of query returns SQL query.

__repr__

The __repr__ method is another special method which gives string representation of the object. Unlike __str__, which is meant to be readable by humans, __repr__ should return a string that represents a valid Python expression that could be used to recreate the object. It's used by the repr() function and the interactive interpreter.

__repr__ means to be read by other developers.

class Point:
def __init__(self, x, y):
self.x = x
self.y = y

def __repr__(self):
return f"Point({self.x}, {self.y})"

point = Point(3, 4)
print(repr(point)) # Output: "Point(3, 4)"

__repr__ can be called by repr function.

repr use cases

  • Serialization: When serializing objects (e.g., to JSON or XML), __repr__ can be used to provide a string representation that can be easily converted back into an object. This is particularly useful in web development and data processing applications.
  • Interactive Console: When working in an interactive Python console (e.g., in an IDE or Jupyter notebook), __repr__ is used to display the result of an expression or variable. Having a meaningful __repr__ implementation makes it easier to understand the content and structure of objects.
  • Logging and Debugging.
In [1]: class Point:
2 def __init__(self, x, y):
3 self.x = x
4 self.y = y
5
6 def __repr__(self):
7 return f"Point({self.x}, {self.y})"

In [2]: p = Point(10, 20)

In [3]: p
Out[3]: Point(10, 20)

In [4]: repr(p)
Out[4]: 'Point(10, 20)'

In [5]: str(p)
Out[5]: 'Point(10, 20)'

__str__ can take __repr__ representation if only __repr__ is defined.

In [9]: class Person:
2 def __init__(self, name, age):
3 self.name = name
4 self.age = age
5
6 def __str__(self):
7 return f"{self.name} - {self.age}"
8
9 p = Person("Alice", 30)
10 print(p)
11 p
Alice - 30
Out[9]: <__main__.Person at 0x771909117a00>

__repr__ will have specific representation only if overridden otherwise it will call base class __repr__.

__format__

The __format__ method allows an object to customize its behavior when used with the format() function or with string formatting using the format() method or f-strings. It takes two arguments: format_spec (the formatting specification) and returns the formatted string.

Let’s create date formatter.

import datetime


class Date:

def __init__(self, year, month, day):
self.date = datetime.datetime(year, month, day)

def __format__(self, format_spec):
if not format_spec:
format_spec = "%D"
return self.date.strftime(format_spec)


date = Date(2024, 4, 15)

print(format(date)) # 04/15/24
print(format(date, "%d/%m/%Y")) # 15/04/2024
print(format(date, "%B %Y")) # April 2024
print(f"{date:%B %Y}") # April 2024

You can refer this PEP to learn more.

Conclusion

Object representation is an essential aspect for understanding an object’s behavior on the fly. The methods we discussed today, such as __str__, __repr__, and __format__, are general-purpose and widely used.

Our goal should be to design objects in a way that helps other developers maintain them in the long run. I sometimes refer to these methods as "metadata methods" because they provide additional details about the object itself.

Hope you find it helpful. Follow Rahul Beniwal for more articles.

Other similar articles by me.

--

--