We're back after a server migration that caused effbot.org to fall over a bit harder than expected. Expect some glitches.

Why can't I use an assignment in an expression?

In Python, assignment is a statement, not an expression, and can therefore not be used inside an arbitrary expression. This means that common C idioms like:

while (line = readline(file)) {
    ...do something with line...
}

or

if (match = search(target)) {
    ...do something with match...
}

cannot be used as is in Python. The first example is better written using an iterator:

for line in file:
    ... do something with line ...

but the second example must be written as:

match = search(target)
if match:
    ... do something with match ...

and loops where an iterator cannot be used have to be written as:

while True:
    line = file.readline()
    if not line:
        break
    ... do something with line ...

(this is often seen in older Python code, since earlier Python versions didn’t support iteration over file objects).

The reason for not allowing assignment in Python expressions is a common, hard-to-find bug in those other languages, caused by this construct:

if (x = 0) {
    ...error handling...
}
else {
    ...code that only works for nonzero x...
}

The error is a simple typo: x = 0, which assigns 0 to the variable x, was written while the comparison x == 0 is certainly what was intended.

Many alternatives have been proposed. Most are hacks that save some typing but use arbitrary or cryptic syntax or keywords, and fail the simple criterion for language change proposals: it should intuitively suggest the proper meaning to a human reader who has not yet been introduced to the construct.

An interesting phenomenon is that most experienced Python programmers recognize the while True idiom and don’t seem to be missing the assignment in expression construct much; it’s only newcomers who express a strong desire to add this to the language.

There’s an alternative way of spelling this that seems attractive, but is generally less robust than the while True solution.

line = f.readline()
while line:
    ...do something with line...
    line = f.readline()

This pattern is known as read ahead, and works well for simple cases, but if you change your mind about exactly how you get the next line (e.g. you want to change it into sys.stdin.readline) you have to remember to change two places in your program — the second occurrence is hidden at the bottom of the loop.

In general, the best approach for looping is to use iterators, and loop through the objects using the for statement. If you need to repeatedly call a function or method to get the next value, you can use the iter wrapper function to turn the callable into an iterator:

for line in iter(f.readline, ""):
    ... do something with line ...

Here, the loop will terminate when it reaches the end of the file (which causes readline to return an empty string).

CATEGORY: general

CATEGORY: design