Right, that's why I said "won't access intermediate scopes"...

On Thursday, January 2, 2014, Steven D'Aprano wrote:
On Thu, Jan 02, 2014 at 02:16:39PM -1000, Guido van Rossum wrote:
> On Thu, Jan 2, 2014 at 3:35 AM, Steven D'Aprano <steve@pearwood.info> wrote:
> > I would have guessed that you could get this working with eval, but if
> > there is such a way, I can't work it out.
> It's trivial if you directly invoke eval():

That's what I thought too, but I get surprising results with

a = b = "global"

def test1():
    b = c = "nonlocal"
    def inner():
        d = "local"
        return (a, b, c, d)
    return inner()

def test2():
    b = c = "nonlocal"
    def inner():
        d = "local"
        c  # Need this or the function fails with NameError.
        return (eval('a'), eval('b'), eval('c'), eval('d'))
    return inner()

assert test1() == test2()  # Fails.

test1() returns ('global', 'nonlocal', 'nonlocal', 'local'), which is
what I expect. But test2() returns ('global', 'global', 'nonlocal', 'local'),
which surprises me.

If I understand what is going on in test2's inner function, eval('b')
doesn't see the nonlocal b so it picks up the global b. (If there is no
global b, you get NameError.) But eval('c') sees the nonlocal c because
we have a closure, due to the reference to c in the previous line.

If there's a way to get eval('b') to return "nonlocal" without having a
closure, I don't know it. This suggests to me that you can't reliably
look-up a nonlocal from an inner function using eval.

Python-ideas mailing list
Code of Conduct: http://python.org/psf/codeofconduct/

--Guido van Rossum (on iPad)