75

Why is Python assignment a statement rather than an expression? If it was an expression which returns the value of the right hand side in the assignment, it would have allowed for much less verbose code in some cases. Are there any issues I can't see?

For example:

# lst is some sequence
# X is come class
x = X()
lst.append(x)

could have been rewritten as:

lst.append(x = X())

Well, to be precise, the above won't work because x would be treated as a keyword argument. But another pair of parens (or another symbol for keyword arguments) would have resolved that.

10
  • What does your code example have to do with the question? Commented Feb 2, 2011 at 1:16
  • @Ignacio: my mistake. The version edited (@Laurence Gonsalves) is good. Commented Feb 2, 2011 at 2:09
  • 2
    "Are there any issues I can't see?" It appears that "much less verbose code" is somehow not a problem. Terse, cryptic code golf seems like an issue. Are you discounting that one for some reason? Commented Feb 2, 2011 at 2:17
  • @S Lott: I guess I was thinking of simple examples (like the one I gave, which I don't see as too cryptic); I agree that the ability to abuse this might be one of the reasons against this feature. Commented Feb 3, 2011 at 17:14
  • I like this question and other questions like it. I believe the answers and comments are very constructive and helpful. I'm just amazed the closure police hasn't shut it down already as NC ;-) Commented Feb 19, 2013 at 9:26

5 Answers 5

52

There are many who feel that having assignments be expressions, especially in languages like Python where any value is allowable in a condition (not just values of some boolean type), is error-prone. Presumably Guido is/was among those who feel that way. The classic error is:

if x = y: # oops! meant to say ==

The situation is also a bit more complicated in Python than it is in a language like C, since in Python the first assignment to a variable is also its declaration. For example:

def f():
    print x

def g():
    x = h()
    print x

In these two functions the "print x" lines do different things: one refers to the global variable x, and the other refers to the local variable x. The x in g is local because of the assignment. This could be even more confusing (than it already is) if it was possible to bury the assignment inside some larger expression/statement.

Sign up to request clarification or add additional context in comments.

20 Comments

The "= vs ==" thing is a red herring. It hasn't been an actual problem in C/C++ for years, ever since compilers learned how to warn about it. I've been using both languages for over ten years and I can't remember the last time I was bitten by that.
@Glenn: Python doesn't have a compiler to warn you, there is no concept of "almost syntax errors" like that.
@Glenn: But since its used at runtime it can't warn about these things in the same sense. Compiler warnings in C are sort of "almost syntax errors", it says "Are you really sure you want this". That concept has no Python equivalent. It's either correct, or it's a syntax error. And Python tries to avoid supporting things that lead newbies to make errors. :-)
@Lennart: Trying to prevent beginners from making beginner mistakes is futile and not--at least not by itself, and at the expense of something else--a good design rationale; and "we can't do that with a warning because our warning system isn't discoverable enough" points at a problem with the warning system or the documentation--you don't design a language around the warning system, you do the reverse.
The point again being that there is no "compile time" in normal usage of the word, as compiling is done on demand during running. Which is the difference I have been pointing out all the time here. It's getting boring repeating myself, so I'm going to stop now.
|
47

Assignment (sub-)expressions (x := y) are supported since Python 3.8 (released Oct. 2019), so you can indeed now rewrite your example as lst.append(x := X()).

The proposal, PEP 572, was formally accepted by Guido in July 2018. There had also been earlier proposals for assignment expressions, such as the withdrawn PEP 379.

Recall that until version 3, print was also a statement rather than an expression.

The statement x = y = z to assign the same value to multiple targets (or rather, multiple target-lists, since unpacking is also permitted) was already supported (e.g. since version 1) but is implemented as a special syntax rather than by chaining successive assignment sub-expressions. Indeed, the order in which the individual assignments are performed is reversed: nested walruses (x := (y := z)) must assign to y before x, whereas x = y = z assigns to x before y (which may be pertinent if you set/assign to the subscripts or attributes of a class that has been overloaded to create some side-effect).

5 Comments

You should just edit the text to contain the current information without the update part :)
BTW, How does a = b = 3 work in the first place when it is not an expression?
@huggie The same way (a*2 for a in b if a) and other compounds work. The entirety of a = b = 3 is one assignment statement, not two expressions as in a = (b:=3). Compare with container literals, which are also of arbitrary element size - (a, b, 3) is not the same as (a, (b, 3)).
It's going in 3.8.
Thanks! Now I can write something like master = [] while(str.lower(n := input('Enter number to append to master or q to quit: ')) != 'q'): master.append(int(n))
15

The real-world answer: it's not needed.

Most of the cases you see this in C are because of the fact that error handling is done manually:

if((fd = open("file", O_RDONLY)) == -1)
{
    // error handling
}

Similarly for the way many loops are written:

while(i++ < 10)
    ;

These common cases are done differently in Python. Error handling typically uses exception handling; loops typically use iterators.

The arguments against it aren't necessarily earth-shattering, but they're weighed against the fact that it simply isn't that important in Python.

1 Comment

Sometimes you may need things like while (x[k] += 1) <= limit: ...; you could rewrite it without the assignment as an expression, but that requires a non-trivial restructuring.
9

I believe this was deliberate on Guido's part in order to prevent certain classic errors. E.g.

if x = 3: print x

when you actually meant to say

if x == 3: ...

I do agree there are times I wished it would work, but I also miss { and } around a block of code, and that sure isn't going to change.

Comments

4
  1. Python's syntax is much less verbose than C's syntax.
  2. It has much more sophisticated scope rules than C.
  3. To use parentheses in every single expression reduces the code readability and python avoids that.

If assigments were expressions, these and many other features would have to be re-worked. For me it is like a deal you have to make in order to have such readable code and useful features. In order to have

if a and (h not in b): ...

rather than

if (a && !(h in b)) { ... }

[not talking about the classic (if a = b:) kind of error.]

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.