Python in Detail: Customizing Str and Repr
Welcome to the Customizing Str and Repr lesson!
This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!
What happens when we call
reprorstron a custom class? By default, they return the same thing.>
class Point:def __init__(self, x, y):self.x = xself.y = y- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
str(Point(3, 5))Result:
- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
repr(Point(3, 5))Result:
These results include the class name and the objects' memory addresses. That lets us tell different objects apart, since they're stored at different memory addresses. But we often want more information than this. For example, these
reprvalues don't tell us the point's.xand.ycoordinates.Fortunately, we can customize
strandreprvia the.__str__and.__repr__dunder methods.>
class Point:def __init__(self, x, y):self.x = xself.y = ydef __repr__(self):return "Point(" + repr(self.x) + ", " + repr(self.y) + ")"- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
center = Point(0, 0)repr(center)Result:
'Point(0, 0)'
We've designed the
.__repr__method to return legal Python code. In this case. that'sPoint(0, 0), which recreates the point object.- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
center = Point(0, 0)center2 = eval(repr(center))(center2.x, center2.y)Result:
(0, 0)
Note that when we build the
"Point(...)"string, we callrepronself.xandself.y. This preserves the coordinates' data types. For example, we might use decimals instead of integers.- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
from decimal import Decimalcenter_of_the_world = Point(Decimal(0), Decimal(0))repr(center_of_the_world)Result:
We can customize
str's behavior in a similar way, by defining.__str__. But often, we don't have to! Conveniently, when an object has a.__repr__but no.__str__, callingstrgives us the.__repr__.- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
gold_location = Point(10, 6)str(gold_location)Result:
'Point(10, 6)'
reprcan be quite verbose for large, complex objects. That's useful when debugging, where that detail helps us to see what's happening. But we wouldn't want to show all of that detail to a user. For strings that we show to users, we can define.__str__with a more compact or simplified value.>
class Point:def __init__(self, x, y):self.x = xself.y = ydef __repr__(self):return "Point(" + repr(self.x) + ", " + repr(self.y) + ")"def __str__(self):return "<" + str(self.x) + ", " + str(self.y) + ">"- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
gold_location = Point(10, 6)str(gold_location)Result:
'<10, 6>'
In some cases, Python calls
strautomatically. For example, it callsstron {interpolated} values in f-strings. (In reality, Python actually calls the.__format__dunder method. But in most cases, that just ends up callingstr(...)for us.)- Note: this code example reuses elements (variables, etc.) defined in earlier examples.
>
gold_location = Point(10, 6)message = f"Go digging at {gold_location}"messageResult:
'Go digging at <10, 6>'
Here's a code problem:
Implement support for
strandrepronUser, using dunder methods and f-strings.str(some_user)should return their name and email address in angle brackets, like "Amir <amir@example.com>".repr(some_user)should return an expression that will recreate the user, likeUser('Amir', 'amir@example.com').- When defining
.__repr__, remember to callrepron the attributes too. For example, if we create a strange user object with integers for its name and email address, we should get an appropriatereprresult likeUser(1, 2).
class User:def __init__(self, name, email):self.name = nameself.email = emaildef __str__(self):return f"{self.name} <{self.email}>"def __repr__(self):return f"User({repr(self.name)}, {repr(self.email)})"amir = User("Amir", "amir@example.com")betty = User("Betty", "betty@example.com")strange_number_user = User(1, 2)assert str(amir) == "Amir <amir@example.com>"assert repr(amir) == "User('Amir', 'amir@example.com')"assert str(betty) == "Betty <betty@example.com>"assert repr(betty) == "User('Betty', 'betty@example.com')"assert str(strange_number_user) == "1 <2>"assert repr(strange_number_user) == "User(1, 2)"- Goal:
None
- Yours:
None