[Python-Dev] Call for prudence about PEP-572

Giampaolo Rodola' g.rodola at gmail.com
Sat Jul 7 09:09:54 EDT 2018


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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20180707/54793a72/attachment.html>


More information about the Python-Dev mailing list