3 ms·
In your example, if you leave out the parentheses around w := bar(), you get "SyntaxError: cannot use assignment expressions with operator" which makes me think
by DangitBobby 5y ago
In your example, if you leave out the parentheses around w := bar(), you get "SyntaxError: cannot use assignment expressions with operator" which makes me think it's a bug in the interpreter and not intentionally designed to allow it.
I am baffled to learn that it's kept in scope outside of the statement it's assigned, and I agree it would have a negative impact on readability if used outside of the if statement.
- dataflow 5y ago> if you leave out the parentheses around w := bar(), you get "SyntaxError: cannot use assignment expressions with operator" which makes me think it's a bug in the interpreter and not intentionally designed to allow it. No, I'm pretty sure that's intentional. You want the left-hand side of an assignment to be crystal clear, which "foo() or w := bar()" is not. It looks like it's assigning to (foo() or w).
- DangitBobby 5y agoTo be clear: def thing(): return True if thing() or w:= "ok": # SyntaxError: cannot use assignment expressions with operator pass print(w) . . . if thing() or (w := "ok"): pass print(w) # NameError: name 'w' is not defined The first error makes me think your concern (that w is conditionally undefined) was anticipated and supposed to be guarded against with the SyntaxError. I believe the fact you can bypass it with parentheses is a bug and not an intentional design decision.
- dataflow 5y agoOh I see, you're looking at it from that angle. But no, it's intentional. Check out PEP 572 [1]: > The motivation for this special case is twofold. First, it allows us to conveniently capture a "witness" for an any() expression, or a counterexample for all(), for example: if any((comment := line).startswith('#') for line in lines): print("First comment:", comment) else: print("There are no comments") I have a hard time believing even the authors (let alone you) could tell me with a straight face that that's easy to read. If they really believe that, I... have questions about their experiences. The beauty of Python... [1] https://www.python.org/dev/peps/pep-0572/ https://www.python.org/dev/peps/pep-0572/
- DangitBobby 5y agoYour new example makes me wonder: if I can intentionally conditionally bring variables into existence with the walrus operator, what's the motivation behind the SyntaxError in my statement above? I maintain my belief that the real issue here is, readability aside, if blocks do not implement a new scope, which has always been a problem in the language. The walrus operator just gives you new ways to trip over that problem. From the PEP: > An assignment expression does not introduce a new scope. In most cases the scope in which the target will be bound is self-explanatory: it is the current scope. If this scope contains a nonlocal or global declaration for the target, the assignment expression honors that. A lambda (being an explicit, if anonymous, function definition) counts as a scope for this purpose. I find this particularly strange and inconsistent: lines = ["1"] [(comment := line).startswith('#') for line in lines] print(comment) # 1 [x for x in range(3)] print(x) # NameError: name 'x' is not defined
- dataflow 5y ago> what's the motivation behind the SyntaxError in my statement above? I'm pretty sure it's what I explained here: https://news.ycombinator.com/item?id=28899404 https://news.ycombinator.com/item?id=28899404
- DangitBobby 5y agoI did not understand what you meant.
- dataflow 5y agoI'm saying it's the same reason why (x + y = z) should be illegal even if (x + (y = z)) is legal in any language. It's not specific to Python by any means. The target of an assignment needs to be obvious and not confusing. You don't want x + y to look like it's being assigned to.
- DangitBobby 5y ago
- deleted 5y ago[deleted]