Skip to content

Commit d125c71

Browse files
committed
Item 55: Use repr strings for debugging output
1 parent 25ad335 commit d125c71

File tree

2 files changed

+122
-0
lines changed

2 files changed

+122
-0
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,12 +546,17 @@ Python 3.
546546
- 3. Module contents can be the product of any external condition, including
547547
host introspection through the sys and os modules.
548548

549+
549550
### []()
550551

552+
551553
### []()
552554

555+
553556
### []()
554557

558+
555559
### []()
556560

561+
557562
### []()

item_55_use_repr_strings.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Item 55: Use repr strings for debugging output
2+
3+
4+
# When debugging a Python program, the print function (or output via the
5+
# logging built-in module) will get you surprisingly far. Python internals are
6+
# often easy to access via plain attributes (see Item 27: "Prefer public
7+
# attributes over private ones"). All you need to do is print how the state of
8+
# your program changes while it runs and see where it goes wrong.
9+
10+
# The print function outputs a human-readable string version of whatever you
11+
# supply it. For example, printing a basic string will print the contents of
12+
# the string without the surrounding quote characters.
13+
14+
# The problem is that the human-readable string for a value doesn't make it
15+
# clear what the actual type of the value is. For example, notice how in the
16+
# default output of print you can't distinguish between the types of the
17+
# number 5 and the string '5'.
18+
19+
print(5)
20+
print('5')
21+
# 5
22+
# 5
23+
24+
# If you're debugging a program with print, these type differences matter.
25+
# What you almost always want while debugging is to see the repr version of an
26+
# object. The repr built-in function returns the printable representation of
27+
# an object, which should be its most clearly understandable string
28+
# representation. For built-in types, the string returned by repr is a valid
29+
# Python expression.
30+
31+
a = '\x07'
32+
print(repr(a))
33+
# '\x07'
34+
35+
# Passing the value from repr to the eval built-in function should result in
36+
# the same Python object you started with (of course, in practice, you should
37+
# only use eval with extreme caution).
38+
39+
b = eval(repr(a))
40+
assert a == b
41+
42+
# When you're debugging with print, you should repr the value before printing
43+
# to ensure that any difference in types is clear.
44+
45+
print(repr(5))
46+
print(repr('5'))
47+
# 5
48+
# '5'
49+
50+
# For dynamic Python objects, the default human-readable string value is the
51+
# same as the repr value. This means that passing a dynamic object to print
52+
# will do the right thing, and you don't need to explicitly call repr on it.
53+
# Unfortunately, the default value of repr for object instances isn't
54+
# especially helpful. For example, here I define a simple class and then print
55+
# its value:
56+
57+
58+
class OpaqueClass(object):
59+
def __init__(self, x, y):
60+
self.x = x
61+
self.y = y
62+
63+
64+
obj = OpaqueClass(1, 2)
65+
print(obj)
66+
print(repr(obj))
67+
# <__main__.OpaqueClass object at 0x7f454b200828>
68+
# <__main__.OpaqueClass object at 0x7f454b200828>
69+
70+
# This output can't be passed to the eval function, and it says nothing about
71+
# the instance fields of the object.
72+
73+
# There are two solutions to this problem. If you have control of the class,
74+
# you can define your own __repr__ special method that returns a string
75+
# containing the Python expression that recreates the object. Here, I define
76+
# that function for the class above:
77+
78+
79+
class BetterClass(object):
80+
def __init__(self, x, y):
81+
self.x = x
82+
self.y = y
83+
84+
def __repr__(self):
85+
return 'BetterClass(%d, %d)' % (self.x, self.y)
86+
87+
88+
# Now, the repr value is much more useful.
89+
90+
obj = BetterClass(1, 2)
91+
print(obj)
92+
print(repr(obj))
93+
# BetterClass(1, 2)
94+
# BetterClass(1, 2)
95+
96+
# When you don't have control over the class definition, you can reach into
97+
# the object's instance dictionary, which is stored in the __dict__
98+
# attribute. Here, I print out the contents of an OpaqueClass instance:
99+
100+
obj = OpaqueClass(4, 5)
101+
print(obj.__dict__)
102+
# {'y': 5, 'x': 4}
103+
104+
105+
# Things to remember
106+
107+
# 1. Calling print on built-in Python types will produce the human-readable
108+
# string version of a value, which hides type information.
109+
# 2. Calling repr on built-in Python types will produce the printable string
110+
# version of a value. These repr strings could be passed to the eval
111+
# built-in function to get back the original value.
112+
# 3. %s in format strings will produce human-readable strings like str.%r will
113+
# produce printable strings like repr.
114+
# 4. You can define the __repr__ method to customize the printable
115+
# representation of a class and provide more detailed debugging
116+
# information.
117+
# 5. You can reach into any object's __dict__ attribute to view its internals.

0 commit comments

Comments
 (0)