[Python-Dev] PEP 572: Assignment Expressions

David Mertz mertz at gnosis.cx
Tue Apr 17 09:01:17 EDT 2018


Strongly agree with Nick that only simple name targets should be permitted
(at least initially). NONE of the motivating cases use more complex
targets, and allowing them encourages obscurity and code golf.

On Tue, Apr 17, 2018, 8:20 AM Nick Coghlan <ncoghlan at gmail.com> wrote:

> On 17 April 2018 at 17:46, Chris Angelico <rosuav at gmail.com> wrote:
> > Syntax and semantics
> > ====================
> >
> > In any context where arbitrary Python expressions can be used, a **named
> > expression** can appear. This is of the form ``target := expr`` where
> > ``expr`` is any valid Python expression, and ``target`` is any valid
> > assignment target.
>
> The "assignment expressions should be restricted to names only"
> subthread from python-ideas finally crystallised for me (thanks in
> part to your own comment that 'With regular assignment (whether it's
> to a simple name or to a subscript/attribute), removing the "target
> :=" part will leave you with the same value - the value of "x := 1" is
> 1.'), and I now have a concrete argument for why I think we want to
> restrict the assignment targets to names only: all complex assignment
> targets create inherent ambiguity around the type of the expression
> result, and exactly which operations are performed as part of the
> assignment.
>
> Initially I thought the problem was specific to tuple unpacking
> syntax, but attempting to explain why subscript assignment and
> attribute assignments were OK made me realise that they're actually
> even worse off (since they can execute arbitrary code on both setting
> and retrieval, whereas tuple unpacking only iterates over iterables).
>
> Tackling those in order...
>
> 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))"?
>     Once you have your answer, what about "a, b, c := iter(range(3))"
> or "a, b, *c := 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))"
>
> 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 for tuple unpacking, does your preferred answer change for the
> case of "seq[:] := iter(range(3))"?
>
>     More generally, if I write  "container[k] := value", does only
> "type(container).__setitem__" get called, or does
> "type(container).__getitem__" get called as well?
>
> Again, this seems inherently ambiguous to me, and hence best avoided
> (at least for now), such that the result is always unambiguously
> "range(3)".
>
> Attribute assignment:
>
>     If I write  "obj.attr := value", does only "type(obj).__setattr__"
> get called, or does "type(obj).__getattribute__" get called as well?
>
> 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.
>
> If all these constructs are prohibited, then a simple design principle
> serves to explain both their absence and the absence of the augmented
> assignment variants: "allowing the more complex forms of assignment as
> expressions makes the order of operations (as well as exactly which
> operations are executed) inherently ambiguous".
>
> That ambiguity generally doesn't exist with simple name bindings (I'm
> excluding execution namespaces with exotic binding behaviour from
> consideration here, as the consequences of trying to work with those
> are clearly on the folks defining and using them).
>
> > The value of such a named expression is the same as the incorporated
> > expression, with the additional side-effect that the target is assigned
> > that value::
> >
> >     # Handle a matched regex
> >     if (match := pattern.search(data)) is not None:
> >         ...
> >
> >     # A more explicit alternative to the 2-arg form of iter() invocation
> >     while (value := read_next_item()) is not None:
> >         ...
> >
> >     # Share a subexpression between a comprehension filter clause and
> its output
> >     filtered_data = [y for x in data if (y := f(x)) is not None]
>
> [snip]
>
> > Style guide recommendations
> > ===========================
> >
> > As this adds another way to spell some of the same effects as can
> already be
> > done, it is worth noting a few broad recommendations. These could be
> included
> > in PEP 8 and/or other style guides.
> >
> > 1. If either assignment statements or assignment expressions can be
> >    used, prefer statements; they are a clear declaration of intent.
> >
> > 2. If using assignment expressions would lead to ambiguity about
> >    execution order, restructure it to use statements instead.
> >
> > 3. Chaining multiple assignment expressions should generally be avoided.
> >    More than one assignment per expression can detract from readability.
>
> Given the many different uses for ":" identified on python-ideas, I'm
> inclined to suggest making these proposed style guidelines more
> prescriptive (at least initially) by either:
>
> 1. Listing out specific approved unambiguous use cases (i.e. if
> statement conditions, while loop conditions, list comprehensions,
> generation expressions)
> 2. Making the 3rd admonition more general by advising against using
> ":" for more than one purpose in the same expression (i.e. don't
> combine assignment expressions with slicing syntax, lambda
> expressions, function headers, variable annotations, dict or set
> displays, dict or set comprehensions)
>
> Cheers,
> Nick.
>
> --
> Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
> _______________________________________________
> 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/mertz%40gnosis.cx
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20180417/acdc57c2/attachment-0001.html>


More information about the Python-Dev mailing list