Skip to content

Commit c7e79fc

Browse files
committed
added item 20
1 parent b24f43e commit c7e79fc

File tree

1 file changed

+110
-0
lines changed

1 file changed

+110
-0
lines changed

item_20.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#!/usr/bin/env python3
2+
3+
'''Item 20 from Effective Python'''
4+
5+
6+
# Example 1
7+
''' print logging messages that are marked with the time of the logged event
8+
'''
9+
print('Example 1:\n==========')
10+
11+
from datetime import datetime
12+
from time import sleep
13+
14+
15+
def log(message, when=datetime.now()):
16+
print('%s: %s' % (when, message))
17+
18+
log('Hi there!')
19+
sleep(0.1)
20+
log('Hi again!')
21+
22+
23+
# Example 2
24+
''' The convention for achieving the desired result in Python is to provide a
25+
default value of None and to document the actual behavior in the docstring.
26+
When your code sees an argument value of None , you allocate the default value
27+
accordingly '''
28+
print('\nExample 2:\n==========')
29+
30+
31+
def log(message, when=None):
32+
"""Log a message with a timestamp.
33+
34+
Args:
35+
message: Message to print.
36+
when: datetime of when the message occurred.
37+
Defaults to the present time.
38+
"""
39+
when = datetime.now() if when is None else when
40+
print('%s: %s' % (when, message))
41+
42+
log('Hi there!')
43+
sleep(0.1)
44+
log('Hi again!')
45+
46+
47+
# Example 3
48+
''' load a value encoded as JSON data. If decoding the data fails, you want an
49+
empty dictionary to be returned by default '''
50+
print('\nExample 3:\n==========')
51+
52+
import json
53+
54+
55+
def decode(data, default={}):
56+
try:
57+
return json.loads(data)
58+
except ValueError:
59+
return default
60+
61+
62+
# Example 4
63+
''' The dictionary specified for default will be shared by all calls to decode
64+
because default argument values are only evaluated once (at module load time).
65+
This can cause extremely surprising behavior '''
66+
print('\nExample 4:\n==========')
67+
68+
foo = decode('bad data')
69+
foo['stuff'] = 5
70+
bar = decode('also bad')
71+
bar['meep'] = 1
72+
print('Foo:', foo)
73+
print('Bar:', bar)
74+
75+
76+
# Example 5
77+
''' The culprit is that foo and bar are both equal to the default parameter.
78+
They are the same dictionary object '''
79+
print('\nExample 5:\n==========')
80+
81+
assert foo is bar
82+
83+
84+
# Example 6
85+
''' The fix is to set the keyword argument default value to None and then
86+
document the behavior in the function's docstring '''
87+
print('\nExample 6:\n==========')
88+
89+
90+
def decode(data, default=None):
91+
""" Load JSON data from a string.
92+
93+
Args:
94+
data: JSON data to decode.
95+
default: Value to return if decoding fails.
96+
DEfaults to an empty dictionary,
97+
"""
98+
if default is None:
99+
default = {}
100+
try:
101+
return json.loads(data)
102+
except ValueError:
103+
return default
104+
105+
foo = decode('bad data')
106+
foo['stuff'] = 5
107+
bar = decode('also bad')
108+
bar['meep'] = 1
109+
print('Foo:', foo)
110+
print('Bar:', bar)

0 commit comments

Comments
 (0)