[Python-ideas] *var()*

Steven D'Aprano steve at pearwood.info
Fri Jan 3 02:18:34 CET 2014


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 at 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 
nonlocals.


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.


-- 
Steven


More information about the Python-ideas mailing list