On Wed, Apr 18, 2018 at 10:13:58AM +1000, Chris Angelico wrote: [regarding comprehensions]
> The changes here are only to edge and corner cases, other than as they > specifically relate to assignment expressions. The current behaviour > is intended to "do the right thing" according to people's > expectations, and it largely does so; those cases are not changing. > For list comprehensions at global or function scope, the ONLY case > that can change (to my knowledge) is where you reuse a variable name: > > [t for t in t.__parameters__ if t not in tvars] > > This works in 3.7 but will fail easily and noisily (UnboundLocalError) > with PEP 572. That's a major semantic change, and the code you show is no better or worse than: t = ... result = [] for t in t.parameters: if t not in tvars: result.append(t) which is allowed. I think you need a better justification for breaking it than merely the opinion: > IMO this is a poor way to write a loop, Reusing names is permitted in Python. If you're going to break code, that surely needs a future import or deprecation period. As you say yourself, you've already found one example in the standard library that will break. > and the fact > that it "happened to work" is on par with code that depended on dict > iteration order in Python 3.2 and earlier. I don't think that's justified. As far as I can tell, the fact that it works is not a mere accident of implementation but a consequence of the promised semantics of comprehensions and Python's scoping rules. If that's not the case, I think you need to justify exactly why it isn't guaranteed. > Yes, the implementation is > well defined, but since you can achieve exactly the same thing by > picking a different variable name, it's better to be clear. Ah, but the aim of the PEP is not to prohibit ugly or unclear code. > Note that the second of the open questions would actually return this > to current behaviour, by importing the name 't' into the local scope. Indeed. Maybe this needs to stop being an open question and become a settled question. > The biggest semantic change is to the way names are looked up at class > scope. Currently, the behaviour is somewhat bizarre unless you think > in terms of unrolling a loop *as a function*; there is no way to > reference names from the current scope, and you will instead ignore > the surrounding class and "reach out" into the next scope outwards > (probably global scope). > > Out of all the code in the stdlib, the *only* one that needed changing > was in Lib/typing.py, where the above comprehension was found. (Not > counting a couple of unit tests whose specific job is to verify this > behaviour.) If there are tests which intentionally verify this behaviour, that really hurts your position that the behaviour is an accident of implementation. It sounds like the behaviour is intended and required. > The potential for breakage is extremely low. Non-zero, but > far lower than the cost of introducing a new keyword, for instance, > which is done without deprecation cycles. Which new keywords are you thinking of? The most recent new keywords I can think of were "True/False", "as" and "with". - True, False became keywords in 3.x during the "breaking code is allowed" 2 -> 3 transition; - "as" became a keyword in 2.6 following a deprecation period in 2.5: py> as = 1 <stdin>:1: Warning: 'as' will become a reserved keyword in Python 2.6 - and "with" needed a __future__ import. Have I missed any? -- Steve _______________________________________________ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com