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

Chris Angelico rosuav at gmail.com
Fri Apr 13 15:24:08 EDT 2018


On Fri, Apr 13, 2018 at 11:18 PM, Steven D'Aprano <steve at pearwood.info> wrote:
> On Fri, Apr 13, 2018 at 09:56:35PM +1000, Chris Angelico wrote:
>
>
>> 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.
>
> I see your point, but why don't we support "with (expr as name):" to
> allow multiple lines? No, don't answer that... its off-topic. Forget I
> asked.

The answer is simple: for the same reason that you can't parenthesize
*most* statements.

>>> for (x in
...     range(5)):
  File "<stdin>", line 2
    range(5)):
             ^
SyntaxError: invalid syntax

It's not an expression, so it doesn't follow the rules of expressions.
There is special grammar around the import statement to permit this,
and anywhere else, if it's not an expression, parens don't work.
(Backslashes do, but that's because they function at a different
level.)

> If we agree that the benefit of putting the expression first is
> sufficiently large, or that the general Pythonic look of "expr as name"
> is sufficiently desirable (it just looks and reads nicely), then we can
> afford certain compromises. Namely, we can rule that:
>
>     except expr as name:
>     with expr as name:
>
> continue to have the same meaning that they have now and never mean
> assignment expressions. Adding parens should not change that.

That's a different sort of special case from what I had in mind, which
is that illegal parenthesization should raise SyntaxError. Either way,
though...

> Yes, that's a special case that breaks the rules, and I accept that it
> is a point against "as". But the Zen is a guideline, not a law of
> physics, and I think the benefits of "as" are sufficient that even
> losing a point it still wins.

... yes, the false parallel is a strike against the "as" syntax.

>> So if it's a bug magnet, what do we do?
>>
>> 1) Permit the subtly different semantics, and tell people to be careful
>
> No.

Agreed.

>> 2) Forbid any use of "(expr as name)" in the header of a 'with' statement
>
> You can't forbid it, because it is currently allowed syntax (albeit
> currently without the parens). So the rule is, it is allowed, but it
> means what it meant pre-PEP 572.

It isn't currently-allowed syntax precisely because of those parens.
So "what it meant pre-PEP 572" is "raise SyntaxError".

>> 3) Forbid it at top level, but permit it deeper down
>
> I don't know what that means. But whatever it means, probably no :-)

That would mean that this is a SyntaxError:

with (get_file() as f):

But this is allowed:

with open(get_filename() as name):

It's a more complicated rule, but a more narrow special case (the ONLY
thing disallowed is the one thing that would be interpreted
differently with and without parens), and there's no ambiguity here.

>> 4) Something else??
>
> Well, there's always the hypothetical -> arrow binding operator, or the
> Pascal := assignment operator (the current preference).
>
> I don't hate the := choice, I just think it is more Pascal-esque that
> Pythonic :-)

That's fair. And since Python has the "==" operator for comparison,
using a Pascal-style ":=" for assignment isn't really paralleling
properly. But purely within Python, any one of the three ('as', ':=',
'->') is going to be at least somewhat viable, and it comes down to
what they parallel *in Python*:

1) 'as' parallels 'import', 'with', and 'except', which perform name
bindings based on some language magic using what's to the left of the
'as'
2) ':=' parallels '=', which takes what's on its right and assigns it
to the target on the left
3) '->' parallels function return value annotations, but looks like
data's moving from the left to the right.

>> > 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.)
>
> I disagree: I think it is a strong parallel. They're both name bindings.
> How much stronger do you want?

True, they're name bindings. So are non-renaming import statements
("import os", "from pprint import pprint"), function and class
definitions, and for loops. None of those use 'as'. So it's a weak
parallel.

> True, we don't currently allow such things as
>
>     import math as maths, mathematics, spam.modules[0]
>
> but we could if we wanted to and there was a sensible use-case for it.

I'm not entirely sure what this would do, partly because I'm unsure
whether it means to import "math" under the name "maths", and the
other two separately, or to import "math" with three targets.

>> There's a strong parallel between "target := value" and "target
>> = value";
>
> Sure. And for a statement, either form would be fine. I just think that
> in an expression, it is important enough to bring the expression to the
> front, even if it requires compromise elsewhere.

Why is it okay for a statement but not an expression? Genuine
question, not scorning it. Particularly since expressions can be used
as statements, so "value -> target" could be used as a statement.

> But whether it is viable or not depends on *us*, not what other
> languages do. No other language choose the syntax of ternary if
> expression before Python used it. We aren't limited to only using syntax
> some other language used first.

Indeed, but for the sake of the PEP, it's useful to cite prior art.
Just wanted to clarify.

> If people agree with me that it is important to put the expression first
> rather than the target name, then the fact that statements and for loops
> put the name first shouldn't matter.
>
> And if they don't, then I'm outvoted :-)

Fair enough. That said, though, consistency DOES have value. The
language fits into people's heads far better if parts of it behave the
same way as other parts. The only question is, which consistencies
matter the most?

ChrisA


More information about the Python-ideas mailing list