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
Chris_Rands
  • 38,994
  • 14
  • 83
  • 119
ryszard
  • 379
  • 1
  • 2
  • 12
  • are you sure you do not want to assign its value to something? – Ma0 Dec 19 '16 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. – tobias_k Dec 19 '16 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 – tobias_k Dec 19 '16 at 16:42

1 Answers1

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
Chris_Rands
  • 38,994
  • 14
  • 83
  • 119
  • 1
    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? – tobias_k Dec 19 '16 at 16:52
  • 2
    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 Dec 19 '16 at 16:58
  • @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 Dec 19 '16 at 17:24
  • @tobias_k I think it follows from [the scoping rules](https://docs.python.org/3/reference/executionmodel.html#resolution-of-names), but I can't really pinpoint it exactly. Maybe someone with a bit more expirience or time can chip in. – syntonym Dec 20 '16 at 09:47