[Python-ideas] Spelling of Assignment Expressions PEP 572 (was post #4)

Chris Angelico rosuav at gmail.com
Fri Apr 13 07:56:35 EDT 2018


On Fri, Apr 13, 2018 at 9:04 PM, Steven D'Aprano <steve at pearwood.info> wrote:
> On Wed, Apr 11, 2018 at 03:32:04PM +1000, Chris Angelico wrote:
>
>> In any context where arbitrary Python expressions can be used, a **named
>> expression** can appear. This can be parenthesized for clarity, and is of
>> the form ``(target := expr)`` where ``expr`` is any valid Python expression,
>> and ``target`` is any valid assignment target.
>
> Have we really decided on spelling this as `target := expression`? You
> list this as a rejected spelling:
>
>
>> 1. ``EXPR as NAME``, with or without parentheses::
>>
>>        stuff = [[f(x) as y, x/y] for x in range(5)]
>
> but I don't think the objections given should be fatal:
>
>>    Omitting the parentheses in this form of the proposal introduces many
>>    syntactic ambiguities.  Requiring them in all contexts leaves open the
>>    option to make them optional in specific situations where the syntax is
>>    unambiguous (cf generator expressions as sole parameters in function
>>    calls), but there is no plausible way to make them optional everywhere.
>>
>>    With the parentheses, this becomes a viable option, with its own tradeoffs
>>    in syntactic ambiguity.  Since ``EXPR as NAME`` already has meaning in
>>    ``except`` and ``with`` statements (with different semantics), this would
>>    create unnecessary confusion or require special-casing.
>
> The special casing you refer to would be to prohibit name binding
> expressions in "except" and "with" statements. You should explicitly say
> so in the PEP.

Parenthesis added to the rejection paragraph.

> I don't think that prohibiting those two forms is a big loss. I think
> any form of
>
>     except (name := expression) as err:
>         do_something(name)
>
> is going to be contrived. Likewise for `with` statements.

I agree as regards except statements. Not so much the with statements,
though. How many times have people asked for "with (expr as name):" to
be supported, allowing the statement to spread over multiple lines?
With this syntax, it would suddenly be permitted - with dangerously
similar semantics. For many MANY context managers, "with (expr as
name):" would do the exact same thing as "with expr as name:". There
is a general expectation that adding parentheses to an expression
usually doesn't change the behaviour, and if it's legal, people will
assume that the behaviour is the same. It isn't, and it's such a
sneaky difference that I would call it a bug magnet.

So if it's a bug magnet, what do we do?

1) Permit the subtly different semantics, and tell people to be careful
2) Forbid any use of "(expr as name)" in the header of a 'with' statement
3) Forbid it at top level, but permit it deeper down
4) Something else??

> I don't especially dislike := but I really think that putting the
> expression first is a BIG win for readability. If that requires parens
> to disambiguate it, so be it.

There's a mild parallel between "(expr as name)" and other uses of
'as', which bind to that name. Every other use of 'as' is part of a
special syntactic form ('import', 'with', and 'except'), but they do
all bind to that name. (Point of interest: You can "with expr as
x[0]:" but none of the other forms allow anything other than a simple
name.) There's a strong parallel between "target := value" and "target
= value"; in fact, the section on the differences is incredibly short
and could become shorter. The only really important difference is that
augmented assignment is not supported (you can't say "x +:= 5"),
partly because it'd mean creating a boatload of three-character
operators for very little value, and partly because
augmented-assignment-as-expression is hard to explain.

Which is better? A weak parallel or a strong one? How important is
putting the expression first? On balance, I'm currently in favour of
the := syntax, but it's only a small difference.

> You also missed the "arrow assignment operator" from various languages,
> including R:
>
>     expression -> name
>
> (In an earlier post, I suggested R's other arrow operator, name <- expr,
> but of course that already evaluates as unary minus expr.)

I actually can't find anything about the -> operator, only the <- one.
(Not that I looked very hard.) Is it a truly viable competitor, or
just one that you'd like to see mentioned for completeness?

> I think that there should be more attention paid to the idea of putting
> the expression first, rather than the name.

How many ways are there to bind a value to a name?

Name last:
* import x as y
* from x import y as z
* except x as y
* with x as y

Name first:
* x = y
* x += y # etc
* for x in y
* def x(.....) ....
* def f(x=1) - arg defaults
* class X: ...

I'm seeing consistency here in that *EVERY* name binding where the
name is at the end uses "as target" as its syntax. Everything else
starts with the target, then defines what's being assigned to it. So I
don't see much value in a "->" operator, except for the mere fact that
it's different (and thus won't conflict in except/with); and the bulk
of name bindings in Python put the name first.

I don't have any really strong arguments in favour of :=, but I have a
few weak ones and a few not quite so weak. So far, I have only weak
arguments in favour of 'as'.

ChrisA


More information about the Python-ideas mailing list