|
| 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