<div id="edo-message"><div>I don't know...to me this looks downright ugly and an awkward special case. It feels like it combines reading difficulty of inline assignment with the awkwardness of a magic word and the ugliness of using ?. Basically, every con of the other proposals combined...<br><br><div id="edo-signature"><pre>--
Ryan (ライアン)
Yoko Shimomura, ryo (supercell/EGOIST), Hiroyuki Sawano >> everyone else
<a href="https://refi64.com/">https://refi64.com/</a></pre></div></div><div id="edo-signature"><pre><br></pre></div></div><div id="edo-original"><div><blockquote type="cite"><div id="edo-meta">On Feb 15, 2018 at 8:07 PM, <<a href="mailto:ncoghlan@gmail.com">Nick Coghlan</a>> wrote: <br><br></div><pre>The recent thread on variable assignment in comprehensions has
<br>prompted me to finally share
<br><a href="https://gist.github.com/ncoghlan/a1b0482fc1ee3c3a11fc7ae64833a315">https://gist.github.com/ncoghlan/a1b0482fc1ee3c3a11fc7ae64833a315</a> with
<br>a wider audience (see the comments there for some notes on iterations
<br>I've already been through on the idea).
<br>
<br>== The general idea ==
<br>
<br>The general idea would be to introduce a *single* statement local
<br>reference using a new keyword with a symbolic prefix: "?it"
<br>
<br>* `(?it=expr)` is a new atomic expression for an "it reference
<br>binding" (whitespace would be permitted around "?it" and "=", but PEP
<br>8 would recommend against it in general)
<br>* subsequent subexpressions (in execution order) can reference the
<br>bound subexpression using `?it` (an "it reference")
<br>* `?it` is reset between statements, including before entering the
<br>suite within a compound statement (if you want a persistent binding,
<br>use a named variable)
<br>* for conditional expressions, put the reference binding in the
<br>conditional, as that gets executed first
<br>* to avoid ambiguity, especially in function calls (where it could be
<br>confused with keyword argument syntax), the parentheses around
<br>reference bindings are always required
<br>* unlike regular variables, you can't close over statement local
<br>references (the nested scope will get an UnboundLocalError if you try
<br>it)
<br>
<br>The core inspiration here is English pronouns (hence the choice of
<br>keyword): we don't generally define arbitrary terms in the middle of
<br>sentences, but we *do* use pronouns to refer back to concepts
<br>introduced earlier in the sentence. And while it's not an especially
<br>common practice, pronouns are sometimes even used in a sentence
<br>*before* the concept they refer to ;)
<br>
<br>If we did pursue this, then PEPs 505, 532, and 535 would all be
<br>withdrawn or rejected (with the direction being to use an it-reference
<br>instead).
<br>
<br>== Examples ==
<br>
<br>`None`-aware attribute access:
<br>
<br>    value = ?it.strip()[4:].upper() if (?it=var1) is not None else None
<br>
<br>`None`-aware subscript access:
<br>
<br>    value = ?it[4:].upper() if (?it=var1) is not None else None
<br>
<br>`None`-coalescense:
<br>
<br>    value = ?it if (?it=var1) is not None else ?it if (?it=var2) is
<br>not None else var3
<br>
<br>`NaN`-coalescence:
<br>
<br>    value = ?it if not math.isnan((?it=var1)) else ?it if not
<br>math.isnan((?that=var2)) else var3
<br>
<br>Conditional function call:
<br>
<br>    value = ?it() if (?it=calculate) is not None else default
<br>
<br>Avoiding repeated evaluation of a comprehension filter condition:
<br>
<br>    filtered_values = [?it for x in keys if (?it=get_value(x)) is not None]
<br>
<br>Avoiding repeated evaluation for range and slice bounds:
<br>
<br>    range((?it=calculate_start()), ?it+10)
<br>    data[(?it=calculate_start()):?it+10]
<br>
<br>Avoiding repeated evaluation in chained comparisons:
<br>
<br>    value if (?it=lower_bound()) <= value < ?it+tolerance else 0
<br>
<br>Avoiding repeated evaluation in an f-string:
<br>
<br>    print(f"{?it=get_value()!r} is printed in pure ASCII as {?it!a}
<br>and in Unicode as {?it}"
<br>
<br>== Possible future extensions ==
<br>
<br>One possible future extension would be to pursue PEP 3150, treating
<br>the nested namespace as an it reference binding, giving:
<br>
<br>    sorted_data = sorted(data, key=?it.sort_key) given ?it=:
<br>        def sort_key(item):
<br>            return item.attr1, item.attr2
<br>
<br>(A potential bonus of that spelling is that it may be possible to make
<br>"given ?it=:" the syntactic keyword introducing the suite, allowing
<br>"given" itself to continue to be used as a variable name)
<br>
<br>Another possible extension would be to combine it references with `as`
<br>clauses on if statements and while loops:
<br>
<br>    if (?it=pattern.match(data)) is not None as matched:
<br>        ...
<br>
<br>    while (?it=pattern.match(data)) is not None as matched:
<br>        ...
<br>
<br>== Why not arbitrary embedded assignments? ==
<br>
<br>Primarily because embedded assignments are inherently hard to read,
<br>especially in long expressions. Restricting things to one pronoun, and
<br>then pursuing PEP 3150's given clause in order to expand to multiple
<br>statement local names should help nudge folks towards breaking things
<br>up into multiple statements rather than writing ever more complex
<br>one-liners.
<br>
<br>That said, the ?-prefix notation is deliberately designed such that it
<br>*could* be used with arbitrary identifiers rather then being limited
<br>to a single specific keyword, and the explicit lack of closure support
<br>means that there wouldn't be any complex nested scope issues
<br>associated with lambda expressions, generator expressions, or
<br>container comprehensions.
<br>
<br>With that approach, "?it" would just be an idiomatic default name like
<br>"self" or "cls" rather than being a true keyword. Given arbitrary
<br>identifier support, some of the earlier examples might instead be
<br>written as:
<br>
<br>    value = ?f() if (?f=calculate) is not None else default
<br>    range((?start=calculate_start()), ?start+10)
<br>    value if (?lower=lower_bound()) <= value < ?lower+tolerance else 0
<br>
<br>The main practical downside to this approach is that *all* the
<br>semantic weight ends up resting on the symbolic "?" prefix, which
<br>makes it very difficult to look up as a new Python user. With a
<br>keyword embedded in the construct, there's a higher chance that folks
<br>will be able to guess the right term to search for (i.e. "python it
<br>expression" or "python it keyword").
<br>
<br>Another downside of this more flexible option is that it likely
<br>*wouldn't* be amenable to the "if expr as name:" syntax extension, as
<br>there wouldn't be a single defined pronoun expression to bind the name
<br>to.
<br>
<br>However, the extension to PEP 3150 would allow the statement local
<br>namespace to be given an arbitrary name:
<br>
<br>    sorted_data = sorted(data, key=?ns.sort_key) given ?ns=:
<br>        def sort_key(item):
<br>            return item.attr1, item.attr2
<br>
<br>Cheers,
<br>Nick.
<br>
<br>--  
<br>Nick Coghlan   |   <a href="mailto:ncoghlan@gmail.com">ncoghlan@gmail.com</a>   |   Brisbane, Australia
<br>_______________________________________________
<br>Python-ideas mailing list
<br><a href="mailto:Python-ideas@python.org">Python-ideas@python.org</a>
<br><a href="https://mail.python.org/mailman/listinfo/python-ideas">https://mail.python.org/mailman/listinfo/python-ideas</a>
<br>Code of Conduct: <a href="http://python.org/psf/codeofconduct/">http://python.org/psf/codeofconduct/</a>
<br></pre></blockquote></div></div>