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

Giampaolo Rodola' g.rodola at gmail.com
Sun Jul 8 05:41:27 EDT 2018


On Sat, Jul 7, 2018 at 5:48 PM Guido van Rossum <guido at python.org> wrote:

> Enforcing such restrictions in the grammar would actually be complicated,
> due to nesting -- but even if it wasn't, I wouldn't want to, as I don't
> want to limit future generations to only the benefits of the new construct
> that we can now come up with. Orthogonality is a good thing in my mind,
> else we might never have had nested functions or conditional imports.
>

Got it.

As to why you might want to use := in a function call, I could imagine
> writing
>
>     if validate(name := re.search(pattern, line).group(1)):
>         return name
>

I meant this case:

    >>> foo(x := 1)   # execute "x = 1" AND "foo(1)"

I find that (space between the parentheses of a function call statement)
too unnatural as a place where to put an assignment. It is not even
"guarded" by a keyword like "if" or  "while" which can help as indicators
that an assignment may occur. Also, I think it's way too easy to confuse it
with a keyword argument:

    >>> foo(x = 1)  # keyword arg
    >>> foo(x := 1)  # assignment + value passing

As for "assert" what I'm concern about is the proliferation of things like
this:

    class Foo:
        def __init__(self):
            assert self.x := fun1()
            assert self.y := fun2()
            assert self.z := fun3()

When I look at that my brain tells me that the main subject of the line is
"assert", not the assignment, but maybe it's just because I'm not used to
it. That aside there's the question of what to do when "python -O" switch
is used. With this in place "-O" would acquire a new meaning, as it would
disable "assert" statements AND assignments.


> On Sat, Jul 7, 2018 at 6:12 AM Giampaolo Rodola' <g.rodola at gmail.com>
> wrote:
>
>> 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 co #
>> execute "foo(1)" AND "x = 1"ncerned 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 at python.org
>> https://mail.python.org/mailman/listinfo/python-dev
>> Unsubscribe:
>> https://mail.python.org/mailman/options/python-dev/guido%40python.org
>>
>
>
> --
> --Guido van Rossum (python.org/~guido)
>


-- 
Giampaolo - http://grodola.blogspot.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20180708/a8bcfe97/attachment-0001.html>


More information about the Python-Dev mailing list