What is the difference between __str__ and __repr__?
Alex summarized well but, surprisingly, was too succinct.
First, let me reiterate the main points in Alex’s post:
- The default implementation is useless (it’s hard to think of one which wouldn’t be, but yeah)
__repr__
goal is to be unambiguous__str__
goal is to be readable- Container’s
__str__
uses contained objects’__repr__
Default implementation is useless
This is mostly a surprise because Python’s defaults tend to be fairly useful. However, in this case, having a default for __repr__
which would act like:
return "%s(%r)" % (self.__class__, self.__dict__)
would have been too dangerous (for example, too easy to get into infinite recursion if objects reference each other). So Python cops out. Note that there is one default which is true: if __repr__
is defined, and __str__
is not, the object will behave as though __str__=__repr__
.
This means, in simple terms: almost every object you implement should have a functional __repr__
that’s usable for understanding the object. Implementing __str__
is optional: do that if you need a “pretty print” functionality (for example, used by a report generator).
The goal of __repr__
is to be unambiguous
Let me come right out and say it — I do not believe in debuggers. I don’t really know how to use any debugger, and have never used one seriously. Furthermore, I believe that the big fault in debuggers is their basic nature — most failures I debug happened a long long time ago, in a galaxy far far away. This means that I do believe, with religious fervor, in logging. Logging is the lifeblood of any decent fire-and-forget server system. Python makes it easy to log: with maybe some project specific wrappers, all you need is a
log(INFO, "I am in the weird function and a is", a, "and b is", b, "but I got a null C — using default", default_c)
But you have to do the last step — make sure every object you implement has a useful repr, so code like that can just work. This is why the “eval” thing comes up: if you have enough information so eval(repr(c))==c
, that means you know everything there is to know about c
. If that’s easy enough, at least in a fuzzy way, do it. If not, make sure you have enough information about c
anyway. I usually use an eval-like format: "MyClass(this=%r,that=%r)" % (self.this,self.that)
. It does not mean that you can actually construct MyClass, or that those are the right constructor arguments — but it is a useful form to express “this is everything you need to know about this instance”.
Note: I used %r
above, not %s
. You always want to use repr()
[or %r
formatting character, equivalently] inside __repr__
implementation, or you’re defeating the goal of repr. You want to be able to differentiate MyClass(3)
and MyClass("3")
.
The goal of __str__
is to be readable
Specifically, it is not intended to be unambiguous — notice that str(3)==str("3")
. Likewise, if you implement an IP abstraction, having the str of it look like 192.168.1.1 is just fine. When implementing a date/time abstraction, the str can be "2010/4/12 15:35:22", etc. The goal is to represent it in a way that a user, not a programmer, would want to read it. Chop off useless digits, pretend to be some other class — as long is it supports readability, it is an improvement.
Container’s __str__
uses contained objects’ __repr__
This seems surprising, doesn’t it? It is a little, but how readable would it be if it used their __str__
?
[moshe is, 3, hello
world, this is a list, oh I don't know, containing just 4 elements]
Not very. Specifically, the strings in a container would find it way too easy to disturb its string representation. In the face of ambiguity, remember, Python resists the temptation to guess. If you want the above behavior when you’re printing a list, just
print("[" + ", ".join(l) + "]")
(you can probably also figure out what to do about dictionaries.
Summary
Implement __repr__
for any class you implement. This should be second nature. Implement __str__
if you think it would be useful to have a string version which errs on the side of readability.
The difference between __str__ and __repr__?
__str__
and __repr__
are both methods for getting a string representation of an object. __str__
is supposed to be shorter and more user-friendly, while __repr__
is supposed to provide more detail.
Specifically, for many data types, __repr__
returns a string that, if you pasted it back into Python, would be a valid expression whose value would be equal to the original value. For instance, str('Hello')
returns 'Hello'
, but repr('Hello')
returns "'Hello'"
, with quote marks inside the string. If you printed that string out, you'd get 'Hello'
, and if you pasted that back into Python, you'd get the original string back.
Some data types, like file objects, can't be converted to strings this way. The __repr__
methods of such objects usually return a string in angle brackets that includes the object's data type and memory address. User-defined classes also do this if you don't specifically define the __repr__
method.
When you compute a value in the REPL, Python calls __repr__
to convert it into a string. When you use print
, however, Python calls __str__
.
When you call print((Item("Car"),))
, you're calling the __str__
method of the tuple
class, which is the same as its __repr__
method. That method works by calling the __repr__
method of each item in the tuple, joining them together with commas (plus a trailing one for a one-item tuple), and surrounding the whole thing with parentheses. I'm not sure why the __str__
method of tuple
doesn't call __str__
on its contents, but it doesn't.
What is the purpose of __str__ and __repr__?
__repr__
Called by the
repr()
built-in function and by string conversions (reverse quotes) to compute the "official" string representation of an object. If at all possible, this should look like a valid Python expression that could be used to recreate an object with the same value (given an appropriate environment).
__str__
Called by the
str()
built-in function and by the print statement to compute the "informal" string representation of an object.
Use __str__
if you have a class, and you'll want an informative/informal output, whenever you use this object as part of string. E.g. you can define __str__
methods for Django models, which then gets rendered in the Django administration interface. Instead of something like <Model object>
you'll get like first and last name of a person, the name and date of an event, etc.
__repr__
and __str__
are similar, in fact sometimes equal (Example from BaseSet
class in sets.py
from the standard library):
def __repr__(self):
"""Return string representation of a set.
This looks like 'Set([<list of elements>])'.
"""
return self._repr()
# __str__ is the same as __repr__
__str__ = __repr__
How are __repr__ and __str__ implemented in print function
The explanation is not very good. I will try another one.
The difference between __repr__
and __str__
lies in the information value. The standard implementation is __repr__
and returns the class and the hash of the instance, which represents the memory address, as this is used by the interpreter for unique identification. It is the unique representation of an object's instance. However, this is not always helpful for the user. This is where __str__
comes into play.
Inheritance is an illustration of a tree structure. Every time you inherit from a class or type, you add another child node to the tree. The deeper you are in the tree, the more information may be available about the individual nodes.
Within my implementation of a tree you can see that the unique identification is given by the class, the module path and the content. However, the actual content of the node is more interesting for the user. However, this can vary depending on the use or depth within the tree.
Due to the amount of data that is collected in a sequence / iterable, it makes more sense to continuously output the __repr__
variant. In my implementation the __str__
output would make no sense, would change constantly and go beyond the scope if I wanted to output the entire tree. So with __str__
I only return the string of the real data. Remember, there may be a node that appears at a different location in the tree but contains the same content. These appear the same but are different.
Unfortunately I can't give you a better explanation. I hope it's not too weird and complicated.
Think about it.
I believe in you!
from abc import ABC
from typing import List
class BaseNode(ABC):
def __init__(self) -> None:
self._children = []
self._parent = None
def __len__(self) -> int:
return len(self._children)
def __repr__(self):
# python default implementation of __repr__
return f'<{self.__class__.__module__}.{self.__class__.__name__}' \
f' object at {self.__hash__()}>'
# python default implementation of __str__
__str__ = __repr__
def has_children(self) -> bool:
return len(self) > 0
def is_leaf(self) -> bool:
return not self.has_children()
def is_root(self) -> bool:
return self._parent is None
def add(self, child: 'BaseNode') -> 'BaseNode':
self._children.append(child)
child._parent = self
return self
def depth(self) -> int:
d,n = 0,self
while not n.is_root():
d,n = d+1,n._parent
return d
def descendants(self) -> List['Node']:
arr = []
if self.is_leaf(): return arr
else:
arr.extend(self._children)
for child in self._children:
arr.extend(child.descendants())
return arr
# abstract
def remove(self, child: 'BaseNode') -> 'BaseNode':
self._children.remove(child)
child._parent = None
return self
class RootNode(BaseNode):
pass
class Node(BaseNode):
def __init__(self, content):
super().__init__()
self._content = content
def __str__(self):
return self.content
@property
def content(self):
return self._content
def main():
node = RootNode()
node_a = Node('Node 1')
node_aa = Node('Node 1.1')
node_ab = Node('Node 1.2')
node_aba = Node('Node 1.2.1')
node_b = Node('Node 2')
node_ba = Node('Node 2.1')
node_ab.add(node_aba)
node_a.add(node_aa)
node_a.add(node_ab)
node.add(node_a)
node_b.add(node_ba)
node.add(node_b)
print(node)
print(str(node))
print(repr(node))
print(node.depth())
print(node.descendants())
print(node_aba)
print(str(node_aba))
print(repr(node_aba))
print(node_aba.depth())
print(node_aba.descendants())
if __name__ == '__main__':
main()
``
repr vs str in python classes - both are given
Basically, __str__()
is called for explicit string conversions, i.e. str(x)
will call x.__str__()
. Some functions like print()
will also perform string conversions of their arguments.
The reason your test code calls __repr__()
rather than __str__()
is that the indentation is off – __str__()
isn't actually part of the class, so it's not called. Otherwise print
would perform a string conversion, but str(x)
falls back to x.__repr__()
if __str__()
is not definied.
Understanding difference between Double Quote and Single Quote with __repr__()
There is no semantic difference between '
and "
. You can use '
if the string contains "
and vice versa, and Python will do the same. If the string contains both, you have to escape some of them (or use triple quotes, """
or '''
). (If both '
and "
are possible, Python and many programmers seem to prefer '
, though.)
>>> x = "string with ' quote"
>>> y = 'string with " quote'
>>> z = "string with ' and \" quote"
>>> x
"string with ' quote"
>>> y
'string with " quote'
>>> z
'string with \' and " quote'
About print
, str
and repr
: print
will print the given string with no additional quotes, while str
will create a string from the given object (in this case, the string itself) and repr
creates a "representation string" from the object (i.e. the string including a set of quotes). In a nutshell, the difference between str
and repr
should be that str
is easy to understand for the user and repr
is easy to understand for Python.
Also, if you enter any expression in the interactive shell, Python will automatically echo the repr
of the result. This can be a bit confusing: In the interactive shell, when you do print(x)
, what you see is str(x)
; when you use str(x)
, what you see is repr(str(x))
, and when you use repr(x)
, you see repr(repr(x))
(thus the double quotes).
>>> print("some string") # print string, no result to echo
some string
>>> str("some string") # create string, echo result
'some string'
>>> repr("some string") # create repr string, echo result
"'some string'"
Why are str(repr(p)) and print(repr(p)) not the same?
The main point of confusion here is around how print
and the REPL work. You can eliminate repr
from the situation entirely and just use string literals to observe when you see the quotes and when you don't:
>>> "foo"
'foo'
>>> print("foo")
foo
>>> x = print("foo")
foo
>>> x
>>> x is None
True
When you see 'foo'
, it's the REPL showing you the (eval
-able) value of the string expression you just typed in. When you see foo
without the quotes, it's a side effect of having called print
, which prints the actual contents of the string. print
also returns None
, as demonstrated by evaluating x is None
after assigning its result to x
. Note that the REPL does not echo None
to the console when it evaluates an expression that returns None
.
python why does it call __str__ instead of __repr__ and why is the print(obj) not working and throws exception
If you hadn't caught the exception (or if you re-raised it to see what you had caught), you would see the problem is with your definitions of __str__
and __repr__
. You are attempting to combine int
and ""
values with +
, and no automatic conversion of int
to str
occurs there.
Traceback (most recent call last):
File "tmp.py", line 19, in <module>
print(obj)
File "tmp.py", line 13, in __str__
return "" + self.obj.tm_hour + ":" + self.obj.tm_min
TypeError: can only concatenate str (not "int") to str
You have to be explicit:
return "" + str(self.obj.tm_hour) + ":" + str(self.obj.tm_min)
or more simply:
return f"{self.obj.tm_hour}:{self.obj.tm_min}"
f-strings do call __str__
as necessary to convert the value inside {...}
to a str
.
Related Topics
Ensure a Single Instance of an Application in Linux
Show Matplotlib Plots (And Other Gui) in Ubuntu (Wsl1 & Wsl2)
How to Generate All Permutations of a List
How to Get Keyboard Input in Pygame
Adding a Scrollbar to a Group of Widgets in Tkinter
What's the Canonical Way to Check For Type in Python
How to Sort a List/Tuple of Lists/Tuples by the Element At a Given Index
How Do "And" and "Or" Act With Non-Boolean Values
Unicodedecodeerror: 'Utf8' Codec Can't Decode Byte 0X9C
What Do I Use on Linux to Make a Python Program Executable
How to Store the Result of an Executed Shell Command in a Variable in Python
How to Add to the Pythonpath in Windows, So It Finds My Modules/Packages
Why Doesn't Calling a String Method Do Anything Unless Its Output Is Assigned
Qtdesigner Changes Will Be Lost After Redesign User Interface
Difference Between Shallow Copy, Deepcopy and Normal Assignment Operation