Context Managers

For the next set of examples we're going to need a data file containing some numbers. Using the code in recaman.py below, we'll write a sequence of numbers called Recaman's sequence to a text file, with one number per line:

import sys
from itertools import count, islice

def sequence():
"""Generate Recaman's sequence."""
seen = set()
a = 0
for n in count(1):
yield a
seen.add(a)
c = a - n
if c < 0 or c in seen:
c = a + n
a = c

def write_sequence(filename, num):
"""Write Recaman's sequence to a text file."""
f = open(filename, mode='wt', encoding='utf-8')
f.writelines("{0} ".format(r)
for r in islice(sequence(), num + 1))
f.close()

if __name__ == '__main__':
write_sequence(filename=sys.argv[1],
num=int(sys.argv[2]))

Recaman's sequence itself isn't important to this exercise; we just needed a way of generating numeric data. As such, we won't be explaining the sequence() generator. Feel free to experiment though.

The module contains a generator for yielding the Recaman numbers and a function which writes the start of the sequence to file using the writelines() method. A generator expression is used to convert each number to a string and add a newline. itertools.islice() is used to truncate the otherwise infinite sequence.

We'll write the first 1000 Recaman numbers to a file by executing the module, passing the filename and series length as command line arguments:

$ python3 recaman.py recaman.dat 1000

Now let's make a complementary module series.py which reads this data file back in:

"""Read and print an integer series."""

import sys

def read_series(filename):
f = open(filename, mode='rt', encoding='utf-8')
series = []
for line in f:
a = int(line.strip())
series.append(a)
f.close()
return series

def main(filename):
series = read_series(filename)
print(series)

if __name__ == '__main__':
main(sys.argv[1])

We simply read one line at a time from the open file, strip the newline with a call to the strip() string method, and convert it to an integer. If we run it from the command line, everything should work as expected:

$ python3 series.py recaman.dat
[0, 1, 3, 6, 2, 7, 13,
...
,3683, 2688, 3684, 2687, 3685, 2686, 3686]

Now let's deliberately create an exceptional situation. Open recaman.dat in a text editor and replace one of the numbers with something that isn't an stringified integer:

0
1
3
6
2
7
13
oops!
12
21

Save the file, and re-run series.py:

$ python3 series.py recaman.dat
Traceback (most recent call last):
File "series.py", line 19, in <module>
main(sys.argv[1])
File "series.py", line 15, in main
series = read_series(filename)
File "series.py", line 9, in read_series
a = int(line.strip())
ValueError: invalid literal for int() with base 10: 'oops!'

The int() constructor raises a ValueError when passed our new, invalid line. The exception is unhandled, and so the program terminates with stack trace.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset