[Python-Dev] assignment expressions: an alternative proposal

Steven D'Aprano steve at pearwood.info
Tue Apr 24 11:15:28 EDT 2018


On Tue, Apr 24, 2018 at 09:50:34AM -0400, Yury Selivanov wrote:
> On Tue, Apr 24, 2018 at 9:46 AM, Nick Coghlan <ncoghlan at gmail.com> wrote:
> > On 24 April 2018 at 23:38, Yury Selivanov <yselivanov.ml at gmail.com> wrote:
> >> I propose to use the following syntax for assignment expressions:
> >>
> >>     ( NAME = expr )
> >>
> >> I know that it was proposed before and this idea was rejected, because
> >> accidentally using '=' in place of '==' is a pain point in
> >> C/C++/JavaScript.
> >>
> >> That said, I believe we can still use this syntax as long as we impose
> >> the following three restrictions on it:
> >>
> >> 1. Only NAME token is allowed as a single target.
> >>
> >> 2. Parenthesis are required.

There are many places where I would use parentheses even if they are 
not required, but being forced to use them when they're not and I don't 
want them is ugly.

I also question why you think this will help prevent accidentally 
writing = when you meant == (equality). Have you never written something 
like this?

    if (x == y) or (a > b): ...

Yes, I know the parens are not strictly needed, since the precedence of 
`or` is lower than the comparison operators. But still, especially for 
complex comparisons, a few extra (round) brackets can improve 
readability.

So now we have:

    if (x = y) or (a > b): ...  # oops


But the biggest problem with this is that it is ambiguous to the human 
reader. At a glance, I'm likely to read x=y in an expression as 
equality. If I notice that it is a single = sign, I'm never going to be 
sure whether it was a mistake or intentional until I study the rest of 
the function minutely.

The benefit of := is that if I see it, I can be pretty sure it was not a 
typo. It is hard to mistype == as := by accident, and they are visually 
distinct enough that I am not going to misread := as == .


> >> 3. Most importantly: it is *not* allowed to mask names in the current
> >> local scope.

That means you can't rebind existing variables. That means you can't 
rebind to the same variable in a loop.

I believe that one of the most important use-cases for binding- 
expression syntax is while loops, like this modified example taken from 
PEP 572 version 3:

    while (data = sock.read()):
        print("Received data:", data)

If you prohibit re-binding data, that prohibits cases like this, or even 
using it inside a loop:

    for value in sequence:
        process(arg, (item = expression), item+1)


Your suggestion to prohibit rebinding variables effectively makes them 
so crippled as to be useless to me.


> > While I agree this would be unambiguous to a computer, I think for
> > most humans it would be experienced as a confusing set of arcane and
> > arbitrary rules about what "=" means in Python.
> 
> I respectfully disagree.  There are no "arcane and confusing rules"
> about "=", it's rather simple:
> 
> "=" is always an assignment.

Why is this allowed?

    x = 1  # both are statement forms
    x = 2

but this is prohibited?

    x = 1
    (x = 2)  # no rebinding is allowed

and even more confusing, this is allowed!

    (x = 1)  # x doesn't exist yet, so it is allowed
    x = 2  # statement assignment is allowed to rebind


By the way, the check for existing variables cannot help to be either 
incomplete or incorrect if you try to do it at compile time:


    from module import *
    (x = 2)  # allowed or not allowed?


If you don't like wild-card imports, how about this:

    if random.random() > 0.5:
        spam = 1
    else:
        eggs = 1
    (spam = 2)  # allowed or not? no way to tell at compile time


But doing the rebinding/shadowing check at runtime will slow down 
binding expressions, and lead to even more arcane and confusing results:

    it = iter("abc")
    while (obj = next(it)):
        print(obj)


will print "a" on the first loop, but then raise an exception on 
the second time loop as obj now exists.



-- 
Steve


More information about the Python-Dev mailing list