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 firstname.lastname@example.org 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.