[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