Python: Input-Output

Interacting with the User

The simplest kind of interaction with the user is to ask a question (given as a string) and read back the answer (also as a string).

The raw_input() function allows to do it.

Returns Function Meaning
str raw_input([str]) Asks a question to the user, returns the answer

Example. Let’s ask the user a simple question:

answer = raw_input("write three space-separated words: ")

print answer
print type(answer)

Here the answer variable contains the user answer. It is always a string; the user decides its actual value.

Now, let’s check if the user answered with exactly three words:

words = answer.split()
print "you wrote", len(words), "words"

reaction_to = {
    True: "Nice!",
    False: "You can do better than that."
}
print reaction_to[len(words) == 3]

Example. Let’s ask the user:

answer = raw_input("write two numbers: ")

print answer
print type(answer)

Let’s print the sum of the two numbers provided by the user. Note that, since the value returned by raw_input() is always a string, we have to first split into words, and then convert the words into (say) floats:

words = answer.split()

n = float(words[0])
m = float(words[1])

print "the sum is", n + m

Of course, if the user can not be split into two words, or if those words do not represent valid float values, the code above will not work.


Reading and Writing Text Files

In order to access the contents of a file (let’s assume a text file for simplicity), we need to first create a handle to it. This can be done with the open() function (see below).

Warning

A handle is simply an object that refers to a given file.

It does not contain any of the file data, but it can be used together with other methods, to read and write from the file it refers to.

Returns Function Meaning
file open(str, [str]) Get a handle to a file
str file.read() Read all the file as a single string
list-of-str file.readlines() Read all lines of the file as a list of strings
str file.readline() Read one line of the file as a string
None file.write(str) Write one string to the file
file.close() Close the file (= flushes changes to disk)

open() allows to get a handle to a file.

The first argument to open() is the path of the file we want to open.

The second argument is optional. It tells open() how we intend to use the file: for reading, for writing, etc.

These are the available access modes:

  1. "r": we want to read from the file. This is the default mode.
  2. "w": we want to write to the file, overwriting its contents.
  3. "a": we want to write to the file, appending to the existing contents.

Mode flags can be combined. For instance:

  • "rw": we want to read and write (in “overwrite” mode).
  • "ra": we want to read and write (in “append” mode).

Once you are done with a file (either reading or writing), make sure to call the close() method to finalize your operations.


Example. Let’s open a file in read-only mode:

handle = open("data/aatable", "r")

print type(handle)

Once we have the file handle, we can read the contents of the file:

  1. As a single, big string:

    all_contents = handle.read()
    print all_contents
    

    read() makes sense if your file is small enough (i.e. it fits into the RAM) and it is not structured as a sequence of lines separated by newline characters.

    Some files fit this description (they are pretty rare, tho).

  2. As a list of lines (strings):

    lines = handle.readlines()
    print lines
    

    readlines() makes sense if your file is small enough and it is structured as a collection of lines.

    FASTA files are an example of such files.

  3. One line at a time, sequentially, from the first onwards:

    line = handle.readline()
    print line
    
    line = handle.readline()
    print line
    
    # etc.
    

    readline() makes sense for very large files, because you can read one line at a time, without saturating the machine.

Given that the handle has been opened in read-only mode (that is, "r") we can not write to it:

>>> handle.write("something something")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: File not open for writing
#        ^^^^^^^^^^^^^^^^^^^^^^^^^
#         Python complains about it!

Warning

Internally, Python keeps track of which lines of a file have already been read. (This is used to implement the readline() method, for instance.)

Once a line has been read, it can not be read from the same file handle.

This limitation affects all three methods: read(), readlines() and readline().

For instance:

handle = open("data/aatable")
# No line has been read yet, so

lines = handle.readlines()
print len(lines)
# I just read *all* of the lines; no unread
# line is left

whats_left = handle.readlines()
print len(whats_left)
# Here Python did *not* read anything, because
# there were no lines left to read!

Example. Let’s see how to write to a file. We have to open a file handle in write mode (either "w" or "a"):

# Open a file for writing
handle = open("result.txt", "w")

# TODO: write a long and complex calculation whose
# result is 42
result = 42

# In order to write the result (which is an int) to the
# file, we have to convert it to a string. Let's also
# add a newline character, so that the result fills a
# whole line.
handle.write(str(result))

# Make sure that our writes are written to disk.
handle.close()

And that’s it.

Warning

Forgetting to close a file opened in read-only mode is not too harmful.

(It is only harmful if you keep opening files and end up with more open files than the Operating System allows. Yes, there is a limit.)

However, forgetting to explicitly close files opened in write mode (either "w", "a" or any other combination including them) can have serious consequences.

The reason is that writes to files are not immediately written to disk, for efficiency. Instead, they are stored in memory until Python decides to write them to the actual file. close() is a way to tell Python to flush the changes to the file.

Intuitively, this means that if you don’t call close() and the program quits (because of an error, for instance), then your changes are not written to the file.


Example. We ask the user the path to a file (it does not matter whether it already exists or not), and then what to write in it:

path = raw_input("give me a path: ")

text = raw_input("give me the contents: ")

handle = open(path, "w")
handle.write("the user replied " + text)
handle.close()

Quiz: what happens if you execute this code twice on the same file?

Now, let’s open the same file, but for reading, and read its contents:

other_handle = open(path, "r")
all_contents = other_handle.read()
other_handle.close()

print "I found:"
print all_contents
print "in the file at", path