111

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.

3
  • 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. :-) Commented Jul 8, 2011 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. Commented Sep 9, 2013 at 9: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. Commented Nov 21, 2014 at 3:18

10 Answers 10

159

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)
Sign up to request clarification or add additional context in comments.

1 Comment

As a side note, an explicit condition may be written as while (line := data.readline()) is not None:
45

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

for line in iter(data.readline, b''):

1 Comment

+1 for being exemplified in the python core documentation: docs.python.org/2/library/functions.html#iter
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 ...

6 Comments

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?
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!)
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.
@NedBatchelder: according to the docs at 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 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.
|
21

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()

4 Comments

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 - 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 :)
A classic while loop, and understandable for any quality of programmer. Probably the best choice for future maintenance purposes.
@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.
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.

Comments

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.

Comments

4

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.

Comments

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.

Comments

2

You could do:

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

1 Comment

That will execute the body of the loop one more time than it is supposed to.
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():
    #...

5 Comments

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.
It should work fine if the function returns an iterator instead of the entire list, correct?
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."
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.
True, but I'm going to leave it like this, since there are already 4 other answers that have for line in data. =D

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.