[Python-ideas] A comprehension scope issue in PEP 572
tim.peters at gmail.com
Sun May 13 02:41:08 EDT 2018
[Tim, suggests changes to the Reference Manual's 4.2.1]
> An assignment expression binds the target, except in a function F
> synthesized to implement a list comprehension or generator expression
> (see XXX). In the latter case, if the target is not in F's
> environment (see section 4.2.2) , the target is bound in the block
> containing F.
Let me try that again ;-) The notion of "environment" includes the
global scope, but that's not really wanted here. "Environment" has
more of a runtime flavor anyway. And since nobody will tell me
anything about class scope, I read the docs myself ;-)
And that's a problem, I think! If a comprehension C is in class scope
S, apparently the class locals are _not_ in C's environment. Since C
doesn't even have read access to S's locals, it seems to me bizarre
that ":=" could _create_ a local in S.
Since I personally couldn't care less about running comprehensions of
any kind at class scope, I propose to make `:=` a SyntaxError if
someone tries to use a comprehension with ':=' at class scope (of
course they may be able to use ":=" in nested comprehensions anyway -
not that anyone would).
If someone objects to that, fine, you figure it out ;-) So here's another stab.
An assignment expression binds the target, except in a function F
synthesized to implement a list comprehension or generator expression
(see XXX). In the latter case:
- If the target also appears as an identifier target of a `for` loop
header in F, a `SyntaxError` exception is raised.
- If the block containing F is a class block, a `SyntaxError`
exception is raised.
- If the target is not local to any function enclosing F, and is not
declared `global` in the block containing F, then the target is bound
in the block containing F.
 The intent is that runtime binding of the target occurs as if the
binding were performed in the block containing F. Because that
necessarily makes the target not local in F, it's an error if the
target also appears in a `for` loop header, which is a local binding
for the same target. If the containing block is a class block, F has
no access to that block's scope, so it doesn't make sense to consider
the containing block. If the target is already known to the
containing block, the target inherits its scope resolution from the
containing block. Else the target is established as local to the
I realize the docs don't generally use bullet lists. Convert to
WallOfText if you must. The material in the footnote would usually go
in a "Rationale" doc instead, but we don't have one of those, and I
think the intent is too hard to deduce without that info.
And repeating the other point, to keep a self-contained account:
> Earlier, for now-necessary disambiguation, I expect that in
> ... targets that are identifiers if occurring in an assignment, ...
> " statement" should be inserted before the comma.
More information about the Python-ideas