<div dir="ltr"><div><div>Sorry in advance for opening yet another topic about PEP-572. With PEP-572 being officially accepted I know debating its inclusion in the language is a useless exercise at this point, but since it's still in "draft" status I would like to express my opinion as I think this is a feature which can potentially be abused fairly easily. FWIW I initially found myself disliking the idea as a whole but <a href="https://github.com/python/cpython/pull/8122">https://github.com/python/cpython/pull/8122</a> made me (and others) reconsider it quite a bit (see: <a href="https://twitter.com/grodola/status/1015251302350245888">https://twitter.com/grodola/status/1015251302350245888</a>). PR-8122 clearly shows an improvement in expressiveness and compactness (many folks argue this is too much) but PEP-572 as it currently stands is too permissive IMHO. My concern about "easily abusable ugly cases" still remains, and I think they should be banned instead of just discouraged in the PEP or in the doc. Since we spend way more time *reading* code rather than writing it, as a "reader" I would expect a more prudent approach to the problem.</div><div><br></div><div>Proposal</div><div>========</div><div><br></div><div>1) allow only one := assignment per line in "if" statements:</div><div>    >>> if x := val1 and y := val2:   # SyntaxError or SyntaxWarning</div><div>    >>> if x == val1 and y := val2:   # SyntaxError or SyntaxWarning</div><div><span style="background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">    >>> if x := val1 and y == val2:   # SyntaxError or SyntaxWarning</span></div><div><span style="background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">    >>> if x := val1:  # OK</span></div><div><span style="background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline">    >>> if (x := val1):  # OK</span><br></div><div><span style="background-color:rgb(255,255,255);text-decoration-style:initial;text-decoration-color:initial;float:none;display:inline"><br></span></div><div>2) allow := in "while" statements, "if" statements and comprehensions only:</div><div>    >>> foo(x := 0)  # SyntaxError</div><div>    >>> yield x := 3  # SyntaxError</div><div>    >>> assert y := 3  # SyntaxError</div><div><br></div><div>3) (debatable) disallow := if the variable is already defined:</div><div>    >>> x = 5</div><div>    >>> if (x := val):  # SyntaxError or SyntaxWarning</div><div><br></div><div>4) ban "a = (b := c)", "x = a := (b := (c := d))" and similar (they're just too ugly IMHO)</div><div><br></div><div>Rationale 1</div><div>===========</div><div><br></div><div>In visual terms assignments in Python have always occurred at the BEGINNING of the line and always on the most LEFT side:</div><div><br></div><div>    >>> foo = fun1()</div><div>    >>> bar = fun2()</div><div>    >>> baz = fun3()</div><div><br></div><div>That is where I naturally expect an assignment to be when reading code. My main concern with PEP-572 is that an assignments can now occur at *any point* in the line:</div><div><br></div><div>    >>> foo = fun1()</div><div>    >>> bar = fun2()</div><div>    >>> if foo == val1 and bar == val2 and baz := fun3():</div><div>    ...    ...</div><div><br></div><div>That forces me to visually scan the whole line horizontally from left to right 'till its end, looking for possible variables being set. I'm concerned that I will miss := occurrences because visually they are very similar to == unless parentheses are made mandatory:</div><div><br></div><div>    >>> if foo == val1 and bar == val2 and (baz := fun3()):</div><div>    ...    ...</div><div><br></div><div>Also, in case of multi-line conditionals I have to visually scan the construct both horizontally AND vertically:</div><div><br></div><div>    >>> if (foo == val1 and \</div><div>    ...        bar == val2 and \</div><div>    ...        baz := val3):</div><div>    ...     ...</div><div><br></div><div>Again, that is not a place where I would expect to find or look for a variable assignment. I know I wouldn't like to read or review a code which does that and I suspect linters will likely end up wanting to emit a warning in that case (see: <a href="https://github.com/PyCQA/pylint/issues/2246">https://github.com/PyCQA/pylint/issues/2246</a>). <a href="https://github.com/python/cpython/pull/8116/files">https://github.com/python/cpython/pull/8116/files</a> avoids using multiple := per line and that's why the result appears readable enough IMO. </div><div><br></div><div>Rationale 2</div><div>===========</div><div><br></div><div>PEP-572 states:</div><div><br></div><div>    > The := operator may be used directly in a positional function call argument</div><div><br></div><div>That means allowing:</div><div><br></div><div>    >>> foo(x := 0)</div><div><br></div><div>I honestly don't see why anyone would want to call a function AND assign a variable value at the same time (except in comprehensions). With this in place I not only have to guard against "if" statements assigning values at any point in the code, but also function calls, both horizontally and vertically e.g.:</div><div><br></div><div>    >>> foo(some_long_var_name, another_one, x := bar(),</div><div>            y := fun())</div><div><br></div><div>To me this looks like the perfect example of where this functionality can be abused. Also, I'm not clear what PEP-572 intend to do about "all other places". E.g. should these cases be allowed? (IMO no)</div><div><br></div><div>    >>> yield x := 3</div><div>    >>> assert y := 3</div><div><br></div><div>--</div><div>Giampaolo - <a href="http://grodola.blogspot.com">http://grodola.blogspot.com</a></div></div><div><br></div></div>