46

I noticed that if I iterate over a file that I opened, it is much faster to iterate over it without reading it first. That is:

l = open('file','r')
for line in l:
    ...

is much faster than

l = open('file','r')
for line in l.read(): 
    ...

or

l = open('file','r')
for line in l.readlines(): 
    ...

The 2nd loop will take around 1.5x as much time (I used timeit over the exact same file, and the results were 0.442 vs. 0.660), and would give the same result.

So, when should I ever use .read() or .readlines?

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Maverick Meerkat
  • 5,737
  • 3
  • 47
  • 66
  • 4
    Please clarify. is the `timeit` measurement for `read`, or for `readlines`? I'd expect the `read` loop to take longer because it returns a single string, so iterating over it would go character-by-character. If your file has on average 100 characters per line, then the code in the `for line in l.read()` loop will execute a hundred times as many times as the code in the `for line in l:` loop. – Kevin Jun 29 '16 at 16:43
  • 1
    it's also for readlines(). Surprisingly there's almost no time difference between read() or readlines()... – Maverick Meerkat Jun 29 '16 at 18:07

5 Answers5

50

The short answer to your question is that each of these three methods of reading bits of a file have different use cases. As noted above, f.read() reads the file as an individual string, and so allows relatively easy file-wide manipulations, such as a file-wide regex search or substitution.

f.readline() reads a single line of the file, allowing the user to parse a single line without necessarily reading the entire file. Using f.readline() also allows easier application of logic in reading the file than a complete line by line iteration, such as when a file changes format partway through.

Using the syntax for line in f: allows the user to iterate over the file line by line as noted in the question.

(As noted in the other answer, this documentation is a very good read):

https://docs.python.org/3/tutorial/inputoutput.html#methods-of-file-objects

Note: It was previously claimed that f.readline() could be used to skip a line during a for loop iteration. However, this doesn't work in Python 2.7, and is perhaps a questionable practice, so this claim has been removed.

LeopardShark
  • 3,820
  • 2
  • 19
  • 33
Checkmate
  • 1,074
  • 9
  • 16
  • 2
    Mixing `readline` with a `for` loop over the file doesn't actually work; `readline` doesn't understand the `next` implementation's buffering. If you want to skip a line in a `for` loop, you should call `next` on the file. – user2357112 Jun 29 '16 at 16:55
  • oh, also if you're using regular expressions to search over the string of the file, than it could be a bit faster than iterating over the file. – Maverick Meerkat Jun 29 '16 at 18:24
3

From the tutorial included in the Python documentation:

When size is omitted or negative, the entire contents of the file will be read and returned; it’s your problem if the file is twice as large as your machine’s memory.... For reading lines from a file, you can loop over the file object. This is memory efficient, fast, and leads to simple code:

>>> for line in f:
...     print(line, end='')
...
This is the first line of the file.
Second line of the file
Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Rudi
  • 95
  • 9
  • That's not an accurate description of the API for either C or Python. – user2357112 Jun 29 '16 at 16:53
  • I figured I wouldn't explain it very well, that's why I pulled the rest of my answer straight from the documentation. – Rudi Jun 29 '16 at 16:54
  • C does not default to reading files line by line. There isn't even a standard function for reading files line by line at all in C; `getline` is a POSIX extension. Also, the loop over `f.read()` does not read the entire file on each iteration, and it does not iterate over the lines. – user2357112 Jun 29 '16 at 17:01
  • I wasn't referring to getline, rather fscanf. – Rudi Jun 29 '16 at 17:21
  • It did last year when I took CS108, not sure when it changed, but I'll be sure to look into it. – Rudi Jun 29 '16 at 17:27
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/115994/discussion-between-rudi-and-user2357112). – Rudi Jun 29 '16 at 17:35
2
#The difference between file.read(), file.readline(), file.readlines()
file = open('samplefile', 'r')
single_string = file.read()    #Reads all the elements of the file 
                               #into a single string(\n characters might be included)
line = file.readline()         #Reads the current line where the cursor as a string 
                               #is positioned and moves to the next line
list_strings = file.readlines()#Makes a list of strings
0

Note that readline() is not comparable to the case of reading all lines in for-loop since it reads line by line and there is an overhead which is pointed out by others already.

I ran timeit on two identical snippts but one with for-loop and the other with readlines(). You can see my snippet below:

  
def test_read_file_1():  
    f = open('ml/README.md', 'r')  
    for line in f.readlines():  
        print(line)  
  
  
def test_read_file_2():  
    f = open('ml/README.md', 'r')  
    for line in f:  
        print(line)  
  
  
def test_time_read_file():  
    from timeit import timeit  
  
    duration_1 = timeit(lambda: test_read_file_1(), number=1000000)  
    duration_2 = timeit(lambda: test_read_file_2(), number=1000000)  
  
    print('duration using readlines():', duration_1)  
    print('duration using for-loop:', duration_2)

And the results:

duration using readlines(): 78.826229238
duration using for-loop: 69.487692794

The bottomline, I would say, for-loop is faster but in case of possibility of both, I'd rather readlines().

Shayan Amani
  • 5,787
  • 1
  • 39
  • 40
0

readlines() is better than for line in file when you know that the data you are interested starts from, for example, 2nd line. You can simply write readlines()[1:].

Such use cases are when you have a tab/comma separated value file and the first line is a header (and you don't want to use additional module for tsv or csv files).

Fibo Kowalsky
  • 1,198
  • 12
  • 23
  • 1
    I think you're getting readline() confused with readlines()? Also pretty sure this object isn't indexible post Python-3 – jon_simon Aug 19 '21 at 06:55
  • 1
    @JonathanSimon you are right, I changed `readline` -> `readlines` – Fibo Kowalsky Aug 22 '21 at 07:00
  • It would be better to just skip the first line of the file explicitly, by reading it before the loop. The real reason for using `.read` or `.readlines` is because you actually want an in-memory copy for some other reason, as explained in the accepted answer. – Karl Knechtel Aug 29 '23 at 19:18