[Python-Dev] Informal educator feedback on PEP 572 (was Re: 2018 Python Language Summit coverage, last part) (original) (raw)
Tim Peters tim.peters at gmail.com
Sun Jun 24 22:46:27 EDT 2018
- Previous message (by thread): [Python-Dev] Informal educator feedback on PEP 572 (was Re: 2018 Python Language Summit coverage, last part)
- Next message (by thread): [Python-Dev] Informal educator feedback on PEP 572 (was Re: 2018 Python Language Summit coverage, last part)
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
[Tim]
. First, the original example I gave would be approximately as well addressed by allowing to declare intended scopes in magically synthesized functions; like (say)
p = None # to establish the intended scope of
p
while any( # split across lines just for readability n % p == 0 for p in smallprimes): n //= p It didn't really require an inline assignment, just a way to override the unwanted (in this case) "allfor
targets are local to the invisible function" rigid consequence of the implementation du jour. [Guido]
Hm, that's more special syntax.
Of course - I'm anticipating that the PEP will be changed to throw out useful assignment expressions in comprehensions, but I still want a way to "export" comprehension for-targets at times ;-)
The nice bit about (b) as currently specified is that it adds no syntax -- it adds a scope rule, but (as IIRC Steven has convincingly argued) few people care about those. Python's scope rules, when fully specified, are intricate to the point of being arcane (e.g. for class scopes) but all that has a purpose -- to make them so DWIM ("Do what I Mean") that in practice you almost never have to worry about them, especially when reading non-obfuscated code (and also when writing, except for a few well-known patterns).
You and Steven and i appear to be on the same page here - but it's in a book nobody else seems to own :-( To me it's just screamingly obvious that
total = 0
cumsums = [total := total + value for value in data]
"should do" what it obviously intends to do - and that the only thing stopping that is a bass-ackwards focus on what most trivially falls out of the current implementation.
...
def f():
y = -1 ys = [y for in range(y := 5)] print(y, ys)
Here
range(y := 5)
is executed in f's scope. Presumably they
iny_ _for
also refers to f's scope, despite thaty
textually appears to be assigned to in the body of the listcomp, and so would - for that reason - expected to be local to the synthesized function, and so raiseUnboundLocalError
when referenced. It's incoherent without detailed knowledge of the implementation. That code should have the same meaning regardless of whether we accept (b) or not -- there is only oney
, in f's scope. I don't mind if we have to add more words to the PEP's scope rules to make this explicit, though I doubt it -- the existing weirdness (in the comprehension spec) about the "outermost iterable" being evaluated in the surrounding scope specifies this. I wouldn't call it incoherent -- I think what I said about scope rules above applies here, it just does what you expect.
Remove "y = -1" and - voila! - we have the dreaded "parent local scoping"
Nick finds so baffling to explain (or so he claims). That is, "has exactly
the same scope in the comprehension as in the parent block, and will create
a local in the latter if the name is otherwise unknown in the parent" comes
with assignment expressions, regardless of whether all such targets
"leak" (the current PEP) or only targets in the expression defining the
iterable of the outermost for
(the PEP without leaking assignment
expressions in comprehensions).
As to whether it "does what you expect", no, not really! In a world where
all binding targets in a comprehension are claimed to be local to the
comprehension, I expect that y := 5
appearing inside the listcomp means
y
is local to the listcomp. "Oh - unless the binding appears in the
expression defining the iterable of the outermost for
" comes from Mars.
Not that it really matters much, but (b) provides consistent semantics in these cases. No need to search Mars for weird exceptions ;-)
...
A "neutral" argument about (b) is that despite the "horrified" reactions that Nick saw, in practice it's going to confuse very few people (again, due to my point about Python's scope rules). I'd wager that the people who might be most horrified about it would be people who feel strongly that the change to the comprehension scope rules in Python 3 is a big improvement, and who are familiar with the difference in implementation of comprehensions (though not generator expressions) in Python 2 vs. 3.
I also doubt it will generally confuse people in practice (to the contrary, I expect they will be confused if things like the cumulative sums example blow up with UnboundLocalError).
But I still don't get the source of the "horror". Assignment expression semantics are wholly consistent with ordinary nested lexical scoping, with or without (b). The only difference is in the scopes picked for assignment expression target names (except for those appearing in the expression defining the iterable yadda yadda yadda). -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.python.org/pipermail/python-dev/attachments/20180624/59df26b9/attachment.html>
- Previous message (by thread): [Python-Dev] Informal educator feedback on PEP 572 (was Re: 2018 Python Language Summit coverage, last part)
- Next message (by thread): [Python-Dev] Informal educator feedback on PEP 572 (was Re: 2018 Python Language Summit coverage, last part)
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]