Skip to content

Commit ef93855

Browse files
committed
Added item_17
1 parent 7f59a99 commit ef93855

File tree

1 file changed

+138
-0
lines changed

1 file changed

+138
-0
lines changed

item_17.py

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
#!/usr/bin/env python3
2+
3+
'''Item 17 from Effective Python'''
4+
5+
6+
# Example 1
7+
''' You'd like to figure out what percentage of overall tourism each city
8+
receives. To do this you need a normalization function '''
9+
print('Example 1:\n==========')
10+
11+
def normalize(numbers):
12+
total = sum(numbers)
13+
result = []
14+
for value in numbers:
15+
percent = 100 * value / total
16+
result.append(percent)
17+
return result
18+
19+
visits = [15, 35, 80]
20+
percentages = normalize(visits)
21+
print(percentages)
22+
23+
24+
# Example 2
25+
''' I can reuse the same function later when I want to compute tourism numbers
26+
for the whole world, a much larger data set '''
27+
print('\nExample 2:\n==========')
28+
29+
path = 'my_numbers.txt'
30+
with open(path, 'w') as f:
31+
for i in (15, 35, 80):
32+
f.write('%d\n' % i)
33+
34+
def read_visits(data_path):
35+
with open(data_path) as f:
36+
for line in f:
37+
yield int(line)
38+
39+
it = read_visits('my_numbers.txt')
40+
percentages = normalize(it)
41+
print(percentages)
42+
43+
44+
# Example 3
45+
''' If you iterate over an iterator or generator that has already raised a
46+
StopIteration exception, you won't get any results the second time around '''
47+
print('\nExample 3:\n==========')
48+
49+
it = read_visits('my_numbers.txt')
50+
print(list(it))
51+
print(list(it)) # Already exhausted
52+
53+
54+
# Example 4
55+
''' you can explicitly exhaust an input iterator and keep a copy of its entire
56+
contents in a list. You can then iterate over the list version of the data as
57+
many times as you need to. '''
58+
print('\nExample 4:\n==========')
59+
60+
def normalize_copy(numbers):
61+
numbers = list(numbers) # Copy the iterator
62+
total = sum(numbers)
63+
result = []
64+
for value in numbers:
65+
percent = 100 * value / total
66+
result.append(percent)
67+
return result
68+
69+
it = read_visits('my_numbers.txt')
70+
percentages = normalize_copy(it)
71+
print(percentages)
72+
73+
74+
# Example 5
75+
''' Copying the iterator could cause your program to run out of memory and
76+
crash. One way around this is to accept a function that returns a new iterator
77+
each time it's called '''
78+
print('\nExample 5:\n==========')
79+
80+
def normalize_func(get_iter):
81+
total = sum(get_iter()) # New iterator
82+
result = []
83+
for value in get_iter(): # New iterator
84+
percent = 100 * value / total
85+
result.append(percent)
86+
return result
87+
88+
percentages = normalize_func(lambda: read_visits(path))
89+
print(percentages)
90+
91+
92+
# Example 6
93+
''' practically speaking you can achieve all of this behavior for your classes
94+
by implementing the __iter__ method as a generator '''
95+
print('\nExample 6:\n==========')
96+
97+
class ReadVisits(object):
98+
def __init__(self, data_path):
99+
self.data_path = data_path
100+
101+
def __iter__(self):
102+
with open(self.data_path) as f:
103+
for line in f:
104+
yield int(line)
105+
106+
visits = ReadVisits(path)
107+
percentages = normalize(visits)
108+
print(percentages)
109+
110+
111+
# Example 7
112+
''' you can write your functions to ensure that parameters aren't just
113+
iterators '''
114+
print('\nExample 7:\n==========')
115+
116+
def normalize_defensive(numbers):
117+
if iter(numbers) is iter(numbers): # An iterator -- bad!
118+
raise TypeError('Must supply a container')
119+
total = sum(numbers)
120+
result = []
121+
for value in numbers:
122+
percent = 100 * value / total
123+
result.append(percent)
124+
return result
125+
126+
visits = [15, 35, 80]
127+
normalize_defensive(visits) # No error
128+
visits = ReadVisits(path)
129+
normalize_defensive(visits) # No error
130+
131+
132+
# Example 8
133+
''' The function will raise an exception if the input is iterable but not a
134+
container '''
135+
print('\nExample 8:\n==========')
136+
137+
it = iter(visits)
138+
normalize_defensive(it)

0 commit comments

Comments
 (0)