[Python-ideas] A comprehension scope issue in PEP 572

Tim Peters tim.peters at gmail.com
Sat May 12 18:11:00 EDT 2018


Just showing an example of "by hand" code emulating nesting of
comprehensions, with a highly dubious rebinding, in the inner
comprehension, of an outer comprehension's local for-target.

list(i + sum((i := i+1) + i for j in range(i))
      for i in range(5))

I don't believe I have compelling use cases for nesting
listcomps/genexps, so that's just made up to be an example of
atrocious feature abuse :-)

In the outer genexp, `i` is obviously local, as is `j` in the inner
genexp.  But the assignment expression in the inner genexp demands
that `i` _there_ be not-local.  To which scope does the inner `i`
belong?  To the same scope it would belong if `i := i+1` were replaced
by `i`, which the docs today say is the outer genexp's scope.  So
that's what it is.

Here's code to emulate all that, with a bit more to demonstrate that
`i` and `j` in the scope containing that statement remain unchanged:
The only "novelty" is that a `nonlocal` declaration is needed to
establish an intended scope.

    def f():
        i = 42
        j = 53
        def outer(it):
            def inner(it):
                nonlocal i
                for j in it:
                    i = i+1
                    yield i
            for i in it:
                yield i + sum(inner(range(i))) + i
        print(list(outer(range(5))))
        print(i, j)
    f()

The output:

    [0, 5, 13, 24, 38]
    42 53

Since the code is senseless, so is the list it generates ;-)  Showing
it this way may make it clearer:

    [0+(0)+0, 1+(2)+2, 2+(3+4)+4, 3+(4+5+6)+6, 4+(5+6+7+8)+8]


More information about the Python-ideas mailing list