[Tutor] eval use (directly by interpreter vs with in a script)

Peter Otten __peter__ at web.de
Sun Nov 2 22:07:19 CET 2014


Alex Kleider wrote:

> I'm puzzled by the following behaviour:
> 
> The following works as I expect:
> 
> alex at x301:~/Python$ python3
> Python 3.4.0 (default, Apr 11 2014, 13:05:18)
> [GCC 4.8.2] on linux
> Type "help", "copyright", "credits" or "license" for more information.
>>>> code = """\
> ... s1 = 'first'
> ... s2 = 'second'
> ... """
>>>> exec(code)
>>>> s1
> 'first'
>>>> s2
> 'second'
>>>> 
> 
> ..the following script also behaves as I expect:
> alex at x301:~/Python$ cat test.py
> #!/usr/bin/env python3
> """
> Testing use of exec().
> """
> code = """\
> s1 = 'first'
> s2 = 'second'
> """
> exec(code)
> print(s1)
> print(s2)
> alex at x301:~/Python$ ./test.py
> first
> second
> 
> ... but this one doesn't:
> alex at x301:~/Python$ cat t1.py
> #!/usr/bin/env python3
> """
> Testing use of exec().
> """
> code = """\
> s1 = 'first'
> s2 = 'second'
> """
> 
> def main():
>      exec(code)
>      print(s1)
> 
> if __name__ == "__main__":
>      main()
> alex at x301:~/Python$ ./t1.py
> Traceback (most recent call last):
>    File "./t1.py", line 15, in <module>
>      main()
>    File "./t1.py", line 12, in main
>      print(s1)
> NameError: name 's1' is not defined
> 
> Any light that can be shed onto this would be appreciated.
> Alex

The function statically determines the scope of names. There is no 
assignment to s1 in main, thus s1 is supposed to be global.

Unlike what one might expect

exec("s1 = 42")

binds the name s1 in the local namespace. On the module level the global and 
local namespace are identical

>>> globals() is locals()
True

so you are effectively assigning a global variable.
Inside a function there is no direct way to get access to the local 
namespace used by exec(). Your options are:

- declare the variable as global

>>> def f():
...     exec("global x; x = 42")
...     print(x)
... 
>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> f()
42
>>> x
42

- pass a dict to exec()

>>> def f():
...     ns = {}
...     exec("x = 42", ns)
...     print(ns["x"])
... 
>>> f()
42

PS: In Python 2 the situation was messy, too, but for this particular setup 
it worked as expected:

>>> def f():
...     exec "x = 42"
...     print x
... 
>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> f()
42
>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

Because exec was a statement the compiler could generate different bytecode 
for functions containing exec.



More information about the Tutor mailing list