[Python-Dev] PEP 572: Assignment Expressions

Tim Peters tim.peters at gmail.com
Tue Apr 17 15:28:06 EDT 2018


I'll channel that Guido would be happiest if this rule were followed:

Given an assignment statement using "=", the meaning is the same if
"=" is replaced with ":=".

In particular, the expression at the far right is evaluated once, and
- in case of chained assignments - is applied in turn to each target
left-to-right.

Otherwise the semantics of "=" and ":=" can be very different indeed.

So, then, e.g., and assuming the rule above always applies:

[Nick]
> Tuple unpacking:
>
>     What's the result type for "a, b, c := range(3)"? Is it a range()
> object? Or is it a 3-tuple? If it's a 3-tuple, is that 3-tuple "(1, 2,
> 3)" or "(a, b, range(3))"?

It's the range object range(3).  Same as in:

    x = a, b, c = range(3)

`x` is bound to the range object range(3).


>     Once you have your answer, what about "a, b, c := iter(range(3))"

A range_iterator object, same as what `x` is bound to in:

    x = a, b, c = iter(range(3))

However, `list(x)` then returns an empty list, because iter(range(3))
was evaluated only once, and the iterator was run to exhaustion when
unpacking it for the `a, b, c` target.

> or "a, b, *c := range(10)"?

The range object range(10).


> Whichever answers we chose would be surprising at least some of the
> time, so it seems simplest to disallow such ambiguous constructs, such
> that the only possible interpretation is as "(a, b, range(3))"

That's why Guido would be happiest with the rule at the top.  "The
answers" can already be surprising at times with current assignment
statements, but they are well defined.  It would be mondo bonkers to
make up entirely different subtle answers ;-)


> Subscript assignment:
>
>     What's the final value of "result" in "seq = list(); result =
> (seq[:] := range(3))"? Is it "range(3)"? Or is it "[1, 2, 3]"?

As above, it's range(3).


>     As for tuple unpacking, does your preferred answer change for the
> case of "seq[:] := iter(range(3))"?

As above, a range_iterator object, but one that's already been run to
exhaustion.


>     More generally, if I write  "container[k] := value", does only
> "type(container).__setitem__" get called, or does
> "type(container).__getitem__" get called as well?

The rule at the top implies __setitem_ is called once, and __getitem__
not at all.  The value of the assignment is the object  `value` was
bound to at the start, regardless of how tricky __setitem__ may be.
And in

    k := container[k] := value

`k` is bound to `value` before `container[k]` is evaluated.  Why?
Because that's how assignment _statements_ have always worked.


> Attribute assignment:
>
>     If I write  "obj.attr := value", does only "type(obj).__setattr__"
> get called, or does "type(obj).__getattribute__" get called as well?

As above, only __setattr__.


> While I can't think of a simple obviously ambiguous example using
> builtins or the standard library, result ambiguity exists even for the
> attribute access case, since type or value coercion may occur either
> when setting the attribute, or when retrieving it, so it makes a
> difference as to whether a reference to the right hand side is passed
> through directly as the assignment expression result, or if the
> attribute is stored and then retrieved again.

This is already defined for assignment statements.  While the PEP
doesn't say "and the same for assignment expressions", my guess is
that it won't be accepted unless it does.

Or, indeed, the target is limited to a name.  But Guido wasn't keen on that.

In short, I think the PEP's chance of acceptance increases the _more_
assignment expressions act like assignment statements, not the less,
and is highest if they act exactly the same (except for returning a
value; e.g., while

>>> a = 3

at a shell displays nothing,

>>> a := 3

should display 3).


More information about the Python-Dev mailing list