Files

This section outlines basic file handling in Python, including file utilities in the numpy package.

File reading

Suppose we create a file with typical input data to our little demo program for evaluating the formula \(s(t)=v_0t + \frac{1}{2}at^2\):

v0 = 2
a = 0.2
dt = 0.1
interval = [0, 2]

We want to read the parameters in the file into Python variables and create a table with columns of \(t\) and \(S(t)\) for \(t\in [0,2]\) with steps of \(\Delta t=0.1\) (as specified by dt and interval in the file).

The code for reading the lines in the file, interpreting them, and assigning values to variables is given next.

infile = open('.input.dat', 'r')
for line in infile:
    # Typical line: variable = value
    variable, value = line.split('=')
    variable = variable.strip()  # remove leading/traling blanks
    if variable == 'v0':
        v0 = float(value)
    elif variable == 'a':
        a = float(value)
    elif variable == 'dt':
        dt = float(value)
    elif variable == 'interval':
        interval = eval(value)
infile.close()

The name of the file is here .input.dat, and it is opened with the parameter 'r' for reading. The for loop for line in infile will read the lines from the file, one by one, and in the current line is available in the string line. To split a line into words separated by a character ‘=’, we use line.split('='), resulting in a list of the words. For example,

>>> line = 'v0 = 5.3'
>>> variable, value = line.split('=')
>>> variable
'v0 '
>>> value
' 5.3'

Note that there are blanks in the strings. Leading and trailing blanks can be removed by variable.strip(). We do this before comparing the variable name with v0, a, etc.

It is important to note that value (the text to the right of = on each line) is a string variable. We need to convert to a float object to get a variable that we can compute with. The assignment interval = eval(value) does some magic and deserve an explanation: eval(s) interprets the text in the string s as Python code. In the present example, value is [0, 2] and this is interpreted as Python code, i.e., as a list, and interval becomes a name for a list object with content [0, 2].

A more modern Python way of opening files is

with open('.input.dat', 'r') as infile:
    for line in infile:
        ...

Now it is not necessary to close the file as it will be automatically done after the with block.

File writing

Suppose we generate \(t\) and \(s(t)\) values in two lists, t_values and s_values, and want to write these as a nicely formatted table to file. The following code does the work:

outfile = open('table1.dat', 'w')
outfile.write('# t    s(t)\n')  # write table header
for t, s in zip(t_values, s_values):
    outfile.write('%.2f  %.4f\n' % (t, s))

Files intended for writing must be opened with a 'w' parameter. The key statement is outfile.write(s) for writing a string to a file (recall that while print automatically adds a newline at the end of the string to be printed, outfile.write(s) does not append a newline so s must contain the newline).

The numpy package contains a convenient function savetxt for saving tabular data. The data must be stored in a two-dimensional numpy array. The savetxt function enables control of the format of the numbers in each column (fmt) through the printf syntax, a header can be added (header) and the header lines begin with a comment character (comment). The code reads

import numpy as np
# Make two-dimensional array of [t, s(t)] values in each row
data = np.array([t_values, s_values]).transpose()

# Write data array to file in table format
np.savetxt('table2.dat', data, fmt=['%.2f', '%.4f'],
           header='t   s(t)', comments='# ')

The tabular data in the file can be read back into a numpy array by the loadtxt function:

data = np.loadtxt('table2.dat', comments='#')

Lines beginning with the comment character are skipped in the reading. The resulting object data is a two-dimensional array: data[i,j] contains row number i and column number j in the table, i.e., data[i,0] holds the \(t\) value and data[i,1] the \(s(t)\) value in the i-th row.