Exercise 20: Functions and Files

Remember your checklist for functions, then do this exercise paying close attention to how functions and files can work together to make useful stuff.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from sys import argv

script, input_file = argv

def print_all(f):
    print f.read()

def rewind(f):
    f.seek(0)

def print_a_line(line_count, f):
    print line_count, f.readline()

current_file = open(input_file)

print "First let's print the whole file:\n"

print_all(current_file)

print "Now let's rewind, kind of like a tape."

rewind(current_file)

print "Let's print three lines:"

current_line = 1
print_a_line(current_line, current_file)

current_line = current_line + 1
print_a_line(current_line, current_file)

current_line = current_line + 1
print_a_line(current_line, current_file)

Pay close attention to how we pass in the current line number each time we run print_a_line.

What You Should See

$ python ex20.py test.txt
First let's print the whole file:

This is line 1
This is line 2
This is line 3

Now let's rewind, kind of like a tape.
Let's print three lines:
1 This is line 1

2 This is line 2

3 This is line 3

Study Drills

  1. Go through and write English comments for each line to understand what's going on.
  2. Each time print_a_line is run, you are passing in a variable current_line. Write out what current_line is equal to on each function call, and trace how it becomes line_count in print_a_line.
  3. Find each place a function is used, and go check its def to make sure that you are giving it the right arguments.
  4. Research online what the seek function for file does. Try pydoc file and see if you can figure it out from there.
  5. Research the shorthand notation += and rewrite the script to use that.

Common Student Questions

What is f in the print_all and other functions?
The f is a variable just like you had in other functions in Exercise 18, except this time it's a file. A file in Python is kind of like an old tape drive on a mainframe, or maybe a DVD player. It has a "read head," and you can "seek" this read head around the file to positions, then work with it there. Each time you do f.seek(0) you're moving to the start of the file. Each time you do f.readline() you're reading a line from the file, and moving the read head to right after the \n that ends that file. This will be explained more as you go on.
Why are there empty lines between the lines in the file?
The readline() function returns the \n that's in the file at the end of that line. This means that print's \n is being added to the one already returned by readline(). To change this behavior simply add a , (comma) at the end of print so that it doesn't print its own \n.
Why does seek(0) not set the current_line to 0?
First, the seek() function is dealing in bytes, not lines. So that's going to the 0 byte (first byte) in the file. Second, current_line is just a variable and has no real connection to the file at all. We are manually incrementing it.
What is +=?
You know how in English I can rewrite "it is" to be "it's"? Or I can rewrite "you are" to "you're"? That's called a contraction, and this is kind of like a contraction for the two operations = and +. That means x = x + y is the same as x += y.
How does readline() know where each line is?
Inside readline() is code that scans each byte of the file until it finds a \n character, then stops reading the file to return what it found so far. The file f is responsible for maintaining the current position in the file after each readline() call, so that it will keep reading each line.

Video