On 7 May 2018 at 11:32, Tim Peters <tim.peters@gmail.com> wrote:
I have a long history of arguing that magically created lexically
nested anonymous functions try too hard to behave exactly like
explicitly typed lexically nested functions, but that's the trendy
thing to do so I always lose ;-) 

You have the reasoning there backwards: implicitly nested scopes behave like explicitly nested scopes because that was the *easy* way for me to implement them in Python 3.0 (since I got to re-use all the pre-existing compile time and runtime machinery that was built to handle explicit lexical scopes). Everything else I tried (including any suggestions made by others on the py3k mailing list when I discussed the problems I was encountering) ran into weird corner cases at either compile time or run time, so I eventually gave up and proposed that the implicit scope using to hide the iteration variable name binding be a full nested closure, and we'd just live with the consequences of that.

The sublocal scoping proposal in the earlier drafts of PEP 572 was our first serious attempt at defining a different way of doing things that would allow names to be hidden from surrounding code while still being visible in nested suites, and it broke people's brains to the point where Guido explicitly asked Chris to take it out of the PEP :)

However, something I *have* been wondering is whether or not it might make sense to allow inline scoping declarations in comprehension name bindings. Then your example could be written:

    def ...:
        p = None
        while any(n % p for nonlocal p in small_primes):
            # p was declared as nonlocal in the nested scope, so our p points to the last bound value

Needing to switch from "nonlocal p" to "global p" at module level would likely be slightly annoying, but also a reminder that the bound name is now visible as a module attribute.

If any other form of comprehension level name binding does eventually get accepted, then inline scope declarations could similarly be used to hoist values out into the surrounding scope:

        rem = None
        while any((nonlocal rem := n % p) for nonlocal p in small_primes):
            # p and rem were declared as nonlocal in the nested scope, so our rem and p point to the last bound value


Nick Coghlan   |   ncoghlan@gmail.com   |   Brisbane, Australia