44

In C, one can do

while( (i=a) != b ) { }

but in Python, it appears, one cannot.

while (i = sys.stdin.read(1)) != "\n":

generates

    while (i = sys.stdin.read(1)) != "\n":
         ^
SyntaxError: invalid syntax

(the ^ should be on the =)

Is there a workaround?

7
  • oh that's awkward... how does readline() compare to raw_input()? Commented Oct 15, 2011 at 22:25
  • 1
    @tekknolagi He probably didn't received your comment. It's a good idea to ping a person by adding @name to the comment text. Commented Oct 15, 2011 at 22:36
  • @JochenRitzel see my comment? sorry :) Commented Oct 15, 2011 at 23:01
  • 1
    The reason why this doesn't work in Python is that assignments are statements and not expressions -- it's simply due to the grammar production rules. Commented Oct 15, 2011 at 23:06
  • 1
    See the Python FAQ for an explanation: Why can’t I use an assignment in an expression?. It advocates iterators or while True instead. Commented Jun 11, 2012 at 18:47

5 Answers 5

44

Starting Python 3.8, and the introduction of assignment expressions (PEP 572) (:= operator), it's now possible to capture an expression value (here sys.stdin.read(1)) as a variable in order to use it within the body of while:

while (i := sys.stdin.read(1)) != '\n':
  do_smthg(i)

This:

  • Assigns sys.stdin.read(1) to a variable i
  • Compares i to \n
  • If the condition is validated, enters the while body in which i can be used
Sign up to request clarification or add additional context in comments.

Comments

27

Use break:

while True:
    i = sys.stdin.read(1)
    if i == "\n":
       break
    # etc...

1 Comment

@FalconMomot This seems like a perfectly reasonable pattern to me. What does it matter where the loop is broken? Either the terminating condition will happen, or it won't. If i == "\n" doesn't happen inside the loop (causing a break), it wouldn't have happened in the while-loop's condition argument either.
9

You can accomplish this using the built-in function iter() using the two-argument call method:

import functools
for i in iter(fuctools.partial(sys.stdin.read, 1), '\n'):
    ...

Documentation for this:

iter(o[, sentinel])
...
If the second argument, sentinel, is given, then o must be a callable object. The iterator created in this case will call o with no arguments for each call to its next() method; if the value returned is equal to sentinel, StopIteration will be raised, otherwise the value will be returned.

One useful application of the second form of iter() is to read lines of a file until a certain line is reached. The following example reads a file until the readline() method returns an empty string:

with open('mydata.txt') as fp:
    for line in iter(fp.readline, ''):
        process_line(line)

Comments

8

A version without functools:

for i in iter(lambda: sys.stdin.read(1), '\n'):

Comments

3

Personally I like imm's and Marks answers using break, but you could also do:

a = None
def set_a(x):
    global a
    a = x
    return a

while set_a(sys.stdin.read(1)) != '\n':
    print('yo')

though I wouldn't recommend it.

Comments

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.