96

I just came across this piece of code

while 1:
    line = data.readline()
    if not line:
        break
    #...

and thought, there must be a better way to do this, than using an infinite loop with break.

So I tried:

while line = data.readline():
    #...

and, obviously, got an error.

Is there any way to avoid using a break in that situation?

Edit:

Ideally, you'd want to avoid saying readline twice... IMHO, repeating is even worse than just a break, especially if the statement is complex.

Community
  • 1
  • 1
user541686
  • 205,094
  • 128
  • 528
  • 886
  • 3
    While this is a good question and I think the `for line in data` solution is a good fit for this specific problem, I don't think there's anything wrong with the `while True: ... break` idiom. Don't be afraid of it. :-) – Kirk Strauser Jul 08 '11 at 22:53
  • 4
    These answers provide alternatives to assignment in the conditional of the while-loop, but really don't answer the question: is there a way to do assignment in the while-loop? I'm running into this same problem, trying to do while (character = string[i]): I *know* that a for-loop is a better way to iterate over a string, but my conditional is actually much more complex than this, and I want to do this assignment as the right-hand side of an "or" within the conditional. –  Sep 09 '13 at 09:30
  • 1
    @KirkStrauser The problem with the break construction is, that it is using four lines to express something, which other languages can do in just one line. However it does the right thing. None of the answers given so far has provided a better general purpose solution. They either only work with iterators or duplicate the assignment, which is worse than three extra lines of code for the break version. – kasperd Nov 21 '14 at 03:18

10 Answers10

132

Starting Python 3.8, and the introduction of assignment expressions (PEP 572) (:= operator), it's now possible to capture the condition value (data.readline()) of the while loop as a variable (line) in order to re-use it within the body of the loop:

while line := data.readline():
  do_smthg(line)
Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190
  • 1
    As a side note, an explicit condition may be written as `while (line := data.readline()) is not None:` – Hi-Angel May 18 '23 at 15:00
44

Try this one, works for files opened with open('filename')

for line in iter(data.readline, b''):
Niklas Claesson
  • 441
  • 1
  • 4
  • 2
30

If you aren't doing anything fancier with data, like reading more lines later on, there's always:

for line in data:
    ... do stuff ...
Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
  • I was trying to play Stump The Sushi Eater by thinking of a type of object `data` might be that would support .readline() but not __iter__(). I'm drawing a blank. Do you know of any offhand? – Kirk Strauser Jul 08 '11 at 22:32
  • Doesn't this require reading the entire file into memory first? That doesn't seem applicable for large files. (Especially if the file is larger than your ram can hold!) – ThorSummoner Oct 15 '14 at 02:48
  • If `data` is a file object (which is an odd name, but that's the way the OP used it), then the entire file will not be read into memory. `for line in data` will iterate over lines, reading them as needed. – Ned Batchelder Oct 15 '14 at 11:37
  • @NedBatchelder: according to the docs at https://docs.python.org/2/library/stdtypes.html#file.next - and my unfortunate experience - the filepointer is not where you'd expect it to be (e.g. for a `data.tell()`) with `for line in data` and might even be at the end of the file even before the last line is read. So, it doesn't quite "read them as needed" if you're counting on python/os to do the accounting of where you are in the file. – mpag Jan 05 '17 at 18:25
  • 1
    @mpag There's definitely no guarantee (and I didn't mean to imply there was) that each line is read precisely as needed. I was countering the notion that the entire file would be read into memory. If you are iterating by lines, you can't make any assumptions about where the file pointer is. – Ned Batchelder Jan 05 '17 at 22:23
  • Is this still true for python 3? – winni2k Aug 17 '17 at 14:35
20

This isn't much better, but this is the way I usually do it. Python doesn't return the value upon variable assignment like other languages (e.g., Java).

line = data.readline()
while line:
    # ... do stuff ... 
    line = data.readline()
cwallenpoole
  • 79,954
  • 26
  • 128
  • 166
dfb
  • 13,133
  • 2
  • 31
  • 52
  • 6
    I'm not a big fan of that, especially if `... do stuff ...` is sizable as it requires you to keep the flow of the entire loop in mind as you hack around on it. For example, if you add something like `if line.startswith('foo'): continue` later without realizing that `line` is only updated at the very end, then you've accidentally created an infinite loop. – Kirk Strauser Jul 08 '11 at 22:22
  • 1
    @Kirk - In part, I agree ,but the alternatives aren't much better. Ideally, the class you're using implements a generator and you can just use a for loop, but there are certain cases where you need a while loop ( e.g., 'while cur_time>expected_time:'). I don't know if the OPs post is much better, but I suppose its a matter of opinion :) – dfb Jul 08 '11 at 22:33
  • A classic while loop, and understandable for any quality of programmer. Probably the best choice for future maintenance purposes. – Kim Jan 24 '19 at 17:09
  • 1
    @Kirk Strauser One could argue if `... do stuff ...` is so long you lost track of what's going on in your loop then you're probably doing it wrong. – arkan Apr 26 '19 at 06:11
7

Like,

for line in data:
    # ...

? It large depends on the semantics of the data object's readline semantics. If data is a file object, that'll work.

Kirk Strauser
  • 30,189
  • 5
  • 49
  • 65
5
for line in data:
    ... process line somehow....

Will iterate over each line in the file, rather than using a while. It is a much more common idiom for the task of reading a file in my experience (in Python).

In fact, data does not have to be a file but merely provide an iterator.

shelhamer
  • 29,752
  • 2
  • 30
  • 33
3

According to the FAQ from Python's documentation, iterating over the input with for construct or running an infinite while True loop and using break statement to terminate it, are preferred and idiomatic ways of iteration.

Mr. Deathless
  • 1,321
  • 14
  • 12
3

If data is a file, as stated in other answers, using for line in file will work fine. If data is not a file, and a random data reading object, then you should implement it as an iterator, implementing __iter__ and next methods.

The next method should to the reading, check if there is more data, and if not, raise StopIteration. If you do this, you can continue using the for line in data idiom.

rafalotufo
  • 3,862
  • 4
  • 25
  • 28
2

You could do:

line = 1
while line:
    line = data.readline()
brandon
  • 1,585
  • 1
  • 10
  • 13
2

If data has a function that returns an iterator instead of readline (say data.iterate), you could simply do:

for line in data.iterate():
    #...
TorelTwiddler
  • 5,996
  • 2
  • 32
  • 39
  • 1
    Don't do that unless you know `data` is tiny (and really not even then) as .readlines() slurps the entire contents into RAM, but it doesn't really buy you anything in return. – Kirk Strauser Jul 08 '11 at 22:30
  • It should work fine if the function returns an iterator instead of the entire list, correct? – TorelTwiddler Jul 08 '11 at 22:38
  • Yes, but I haven't seen .readlines() implemented that way. The docs for file.readlines() say that it will "[r]ead until EOF using readline() and return a list containing the lines thus read." – Kirk Strauser Jul 08 '11 at 22:49
  • I like that answer better. :-) However, the usual name for `iterate` is `__iter__`, and then you can re-write the loop as `for line in data`. – Kirk Strauser Jul 08 '11 at 22:55
  • True, but I'm going to leave it like this, since there are already 4 other answers that have `for line in data`. =D – TorelTwiddler Jul 08 '11 at 23:02