8

Why does Python's eval not work inside a function? The same eval(compile(cmd)) code works in a global environment, but does not work inside the foo function.

Simple example:

fn = '/tmp/tmp'
mode = 'single'

def foo(cmd, fn, mode):
    eval(compile(cmd, fn, mode)) # <<< this does not work
    print 'foo: cmd=', cmd
    print 'foo: x=', x

cmd = "x = 1"
eval(compile(cmd, fn, mode)) # <<< this works
print 'global scope: cmd=', cmd
print 'global scope: x=', x

del(x)
foo('x = 9', fn, mode)

This is the output and error message:

global scope: cmd= x = 1
global scope: x= 1
foo: cmd= x = 9
foo: x=
Traceback (most recent call last):
  File "ctest.py", line 20, in <module>
    foo('x = 9', fn, mode)
  File "ctest.py", line 12, in foo
    print 'foo: x=', x
NameError: global name 'x' is not defined
3
  • are you sure you do not want to assign its value to something? Commented Dec 19, 2016 at 16:20
  • Just tried this: x ends up in the locals dict, just as it does with exec, but while exec(cmd) works within the function, eval(compile(...)) does not. Commented Dec 19, 2016 at 16:34
  • Also, if you put eval("x") instead of x in print 'foo: x=', x it works, too. Same behaviour in both, Python 2.7 and Python 3.4 Commented Dec 19, 2016 at 16:42

1 Answer 1

4

In your function, the execution does work but x ends up in locals(), and then the print statement tries to find x in globals() and so raises the NameError.

fn = '/tmp/tmp'
mode = 'single'

def foo(cmd, fn, mode):
    eval(compile(cmd, fn, mode))
    print 'locals:', locals()
    print 'foo: cmd=', cmd
    print 'foo: x=', locals()['x']

cmd = "x = 1"
eval(compile(cmd, fn, mode))
print 'global scope: cmd=', cmd
print 'global scope: x=', x

del(x)
foo('x = 9', fn, mode)

Outputs:

global scope: cmd= x = 1
global scope: x= 1
locals: {'x': 9, 'cmd': 'x = 9', 'mode': 'single', 'fn': '/tmp/tmp'}
foo: cmd= x = 9
foo: x= 9
Sign up to request clarification or add additional context in comments.

4 Comments

Just noticed that with exec, x does indeed end up in both globals and locals; at first I thought both would yield identical globals and locals. But, yes, why does it not look into locals, and why does eval("x") work, where x fails?
I think the scope of a variable in a function is determined at definition time. Thus things like a = "a"; def print_a(): print(a); a="c" will throw an UnboundLocalError. eval("x") "creates a new complete lookup" and thus can look into the local scope.
@syntonym That's an interesting theory that makes some sense, given your example, and would explain the behaviour. Can you provide a reference for that?
@tobias_k I think it follows from the scoping rules, but I can't really pinpoint it exactly. Maybe someone with a bit more expirience or time can chip in.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.