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 https://github.com/python/cpython/pull/8122 made me (and others) reconsider it quite a bit (see: https://twitter.com/grodola/status/1015251302350245888). 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.
Proposal ======== 1) allow only one := assignment per line in "if" statements: >>> if x := val1 and y := val2: # SyntaxError or SyntaxWarning >>> if x == val1 and y := val2: # SyntaxError or SyntaxWarning >>> if x := val1 and y == val2: # SyntaxError or SyntaxWarning >>> if x := val1: # OK >>> if (x := val1): # OK 2) allow := in "while" statements, "if" statements and comprehensions only: >>> foo(x := 0) # SyntaxError >>> yield x := 3 # SyntaxError >>> assert y := 3 # SyntaxError 3) (debatable) disallow := if the variable is already defined: >>> x = 5 >>> if (x := val): # SyntaxError or SyntaxWarning 4) ban "a = (b := c)", "x = a := (b := (c := d))" and similar (they're just too ugly IMHO) Rationale 1 =========== In visual terms assignments in Python have always occurred at the BEGINNING of the line and always on the most LEFT side: >>> foo = fun1() >>> bar = fun2() >>> baz = fun3() 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: >>> foo = fun1() >>> bar = fun2() >>> if foo == val1 and bar == val2 and baz := fun3(): ... ... 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: >>> if foo == val1 and bar == val2 and (baz := fun3()): ... ... Also, in case of multi-line conditionals I have to visually scan the construct both horizontally AND vertically: >>> if (foo == val1 and \ ... bar == val2 and \ ... baz := val3): ... ... 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: https://github.com/PyCQA/pylint/issues/2246). https://github.com/python/cpython/pull/8116/files avoids using multiple := per line and that's why the result appears readable enough IMO. Rationale 2 =========== PEP-572 states: > The := operator may be used directly in a positional function call argument That means allowing: >>> foo(x := 0) 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.: >>> foo(some_long_var_name, another_one, x := bar(), y := fun()) 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) >>> yield x := 3 >>> assert y := 3 -- Giampaolo - http://grodola.blogspot.com
_______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com