Great work Chris! Thank you!

I do not know whether this is good or bad, but this PEP considers so many
different topics, although closely interrelated with each other.

2018-04-11 8:32 GMT+03:00 Chris Angelico <>:

> Alterations to comprehensions
> -----------------------------
> The current behaviour of list/set/dict comprehensions and generator
> expressions has some edge cases that would behave strangely if an
> assignment
> expression were to be used. Therefore the proposed semantics are changed,
> removing the current edge cases, and instead altering their behaviour
> *only*
> in a class scope.
> As of Python 3.7, the outermost iterable of any comprehension is evaluated
> in the surrounding context, and then passed as an argument to the implicit
> function that evaluates the comprehension.
> Under this proposal, the entire body of the comprehension is evaluated in
> its implicit function. Names not assigned to within the comprehension are
> located in the surrounding scopes, as with normal lookups. As one special
> case, a comprehension at class scope will **eagerly bind** any name which
> is already defined in the class scope.
I think this change is important one no matter what will be the future of
the current PEP. And since it breaks backward compatibility it deserves a
separate PEP.

> Open questions
> ==============
> Can the outermost iterable still be evaluated early?
> ----------------------------------------------------
> As of Python 3.7, the outermost iterable in a genexp is evaluated early,
> and
> the result passed to the implicit function as an argument.  With PEP 572,
> this
> would no longer be the case. Can we still, somehow, evaluate it before
> moving
> on? One possible implementation would be::
>     gen = (x for x in rage(10))
>     # translates to
>     def <genexp>():
>         iterable = iter(rage(10))
>         yield None
>         for x in iterable:
>             yield x
>     gen = <genexp>()
>     next(gen)
> This would pump the iterable up to just before the loop starts, evaluating
> exactly as much as is evaluated outside the generator function in Py3.7.
> This would result in it being possible to call ``gen.send()`` immediately,
> unlike with most generators, and may incur unnecessary overhead in the
> common case where the iterable is pumped immediately (perhaps as part of a
> larger expression).
Previously, there was an alternative _operator form_  `->`  proposed by
Steven D'Aprano. This option is no longer considered? I see several
advantages with this variant:
1. It does not use `:` symbol which is very visually overloaded in Python.
2. It is clearly distinguishable from the usual assignment statement and
it's `+=` friends
There are others but they are minor.

> Frequently Raised Objections
> ============================
> Why not just turn existing assignment into an expression?
> ---------------------------------------------------------
> C and its derivatives define the ``=`` operator as an expression, rather
> than
> a statement as is Python's way.  This allows assignments in more contexts,
> including contexts where comparisons are more common.  The syntactic
> similarity
> between ``if (x == y)`` and ``if (x = y)`` belies their drastically
> different
> semantics.  Thus this proposal uses ``:=`` to clarify the distinction.
> This could be used to create ugly code!
> ---------------------------------------
> So can anything else.  This is a tool, and it is up to the programmer to
> use it
> where it makes sense, and not use it where superior constructs can be used.
But the ugly code matters, especially when it comes to Python. For me, the
ideal option would be the combination of two rejected parts:

Special-casing conditional statements
> -------------------------------------
> One of the most popular use-cases is ``if`` and ``while`` statements.
> Instead
> of a more general solution, this proposal enhances the syntax of these two
> statements to add a means of capturing the compared value::
>     if, text) as match:
>         print("Found:",
> This works beautifully if and ONLY if the desired condition is based on the
> truthiness of the captured value.  It is thus effective for specific
> use-cases (regex matches, socket reads that return `''` when done), and
> completely useless in more complicated cases (eg where the condition is
> ``f(x) < 0`` and you want to capture the value of ``f(x)``).  It also has
> no benefit to list comprehensions.
> Advantages: No syntactic ambiguities. Disadvantages: Answers only a
> fraction
> of possible use-cases, even in ``if``/``while`` statements.

(+ in `while`) combined with this part:

3. ``with EXPR as NAME``::
>        stuff = [(y, x/y) with f(x) as y for x in range(5)]
>    As per option 2, but using ``as`` rather than an equals sign. Aligns
>    syntactically with other uses of ``as`` for name binding, but a simple
>    transformation to for-loop longhand would create drastically different
>    semantics; the meaning of ``with`` inside a comprehension would be
>    completely different from the meaning as a stand-alone statement, while
>    retaining identical syntax.

I see no benefit to have the assignment expression in other places. And all
your provided examples use `while` or `if` or some form of comprehension. I
also see no problem with `if (, text) as match) is not
None:..`.  What is the point of overloading language with expression that
will be used only in `while` and `if` and will be rejected by style
checkers in other places?

With kind regards,
Python-ideas mailing list
Code of Conduct:

Reply via email to