[Courses] [python] No lesson -- open discussion

Andreas Thienemann andreas.thienemann at booking.com
Mon Aug 22 09:44:31 UTC 2011


On 08/21/2011 10:51 PM, Leslie wrote:

> 	First, thanks for this excellent course!
> 	I do have a question about file I/O.
> 	I had the objective of opening a file containing several lines, and
> adding lines to it.  How I solved this is probably awkward. Is there a
> better procedure or any general comments you have about working with
> files?
> I start with myfile.txt which has 2 lines:
>
> This is line 1 of my file.
> This is line 2 of my file.
>
> Then, interactively:
>>>> import os, subprocess, sys
>>>> mylist = ["This is line 3 of my file.\n", "This is line 4 of my
> file.\n"]
>>>> f = open("myfile.txt", "a")
>>>> for i in mylist:
> ...     f.write(i)
> ...
>>>> f.close()

This is actually pretty straightforward. One suggestion from me would be 
to not define the \n newline marker in the myline list but to just add 
it with the write() function. So while staying close to your code:

 >>> mylist = ["This is line 3 of my file.", "This is line 4 of my file."]
 >>> f = open("myfile.txt", "a")
 >>> for i in mylist:
...     f.write(i + "\n")
...
 >>> f.close()

This makes sure that each string will be ending up on it's own line and 
you can't make the mistake of accidentally forgetting the "\n".


Just for kicks, you can even do it without the loop by using the join() 
function which joins a string with a separator. If you chose \n as the 
separator, you get exactly what you want.

 >>> mylist = ["This is line 3 of my file.", "This is line 4 of my file."]
 >>> f = open("myfile.txt", "a")
 >>> f.write("\n".join(mylist))
 >>> f.close()



>>>> x = subprocess.Popen(["cat","myfile.txt"], stdout=subprocess.PIPE)
>>>> for line in x.stdout:
> ...     print line
> ...
> I get what I'm expecting (I closed the spaces to make this shorter),
> namely:
>
> This is line 1 of my file.
> This is line 2 of my file.
> This is line 3 of my file.
> This is line 4 of my file.
>
> Although it works, I am not sure this is the best way to add lines from
> a list.  And if I wanted to append one file to another, is there a
> straightforward way?

The adding of lines is totally fine.

But the reading part could be improved. The execution of cat on the 
shell just to read a file is needlessly complicated. After all, python 
gives you all the parts you need to read a file. No need to fall back 
onto the shell.

There are a few ways to handle that:

Open the file for reading first:
 >>> f = open("myfile.txt", "r")
 >>>

Read everything into a single string:
 >>> f.read()
'This is line 1 of my file.\nThis is line 2 of my file.\nThis is line 3 
of my file.\nThis is line 4 of my file.\n'
 >>>

You are now at the end of the file. If you read again, you won't get 
anything:
 >>> f.read()
''
 >>>

To read from the beginning again, you have to "rewind" your file to the 
beginning. The command is called seek() and takes a position in bytes. 0 
is always the beginning of the file:
 >>> f.seek(0)
 >>>

Read your file, line by line. This will read the first line and then stop.
 >>> print f.readline()
This is line 1 of my file.

 >>>
Did you notice the linebreak \n? It is read and printed to the terminal, 
resulting in a visible linebreak.

Let's use readline() a few more times and see what we get.
 >>> print f.readline()
This is line 2 of my file.

 >>> print f.readline()
This is line 3 of my file.

 >>> print f.readline()
This is line 4 of my file.

 >>> print f.readline()

 >>>

You are now at the end of the file. By putting this into a loop, you've 
already implemented the functionality to read a file and print it to the 
screen.

Or us the readlines() function which reads all lines of a file into a 
list. This is handy for nearly all files. But be careful with huge files 
as this means you'd be loading it all into memory:
 >>> f.seek(0)
 >>> f.readlines()
['This is line 1 of my file.\n', 'This is line 2 of my file.\n', 'This 
is line 3 of my file.\n', 'This is line 4 of my file.\n']
 >>>

You can use that in a loop as well and print the line with a bit of 
decoration, e.g. the filename:
 >>> f.seek(0)
 >>> for l in f.readlines():
...     print "myfile.txt:", l[:-1]
...
myfile.txt: This is line 1 of my file.
myfile.txt: This is line 2 of my file.
myfile.txt: This is line 3 of my file.
myfile.txt: This is line 4 of my file.
 >>>

After all is done, just close the file:
 >>> f.close()
 >>>

These are all more pythonesque ways of reading files.

cheers,
  andreas


More information about the Courses mailing list