python exec behaves inconsistent with respect to module imports

Peter Otten __peter__ at web.de
Wed Sep 5 10:11:12 EDT 2007


Am Wed, 05 Sep 2007 13:12:24 +0000 schrieb carl.dhalluin at gmail.com:

> I am completely puzzled why the following exec code does not work:
> 
> mycode = "import math\ndef f(y):\n    print math.floor(y)\nf(3.14)"
> def execute():
>     exec mycode
> execute()
> 
> 
> I get the error:
> 
> root at devmachine1:/opt/qbase# python error1.py
> Traceback (most recent call last):
>   File "error1.py", line 5, in ?
>     execute()
>   File "error1.py", line 4, in execute
>     exec mycode
>   File "<string>", line 4, in ?
>   File "<string>", line 3, in f
> NameError: global name 'math' is not defined
 
> Note that the following code _does_ work:
> 
> mycode = "import math\ndef f(y):\n    print math.floor(y)\nf(3.14)"
> exec mycode
 
> I have tested this in python 2.3 and 2.4.

exec breaks nested namespaces here.

Essentially

exec "import math"

puts the "math" name into the local namespace, but

"def f(): math.floor"

looks up "math" in the global namespace. On the module level global and
local namespace are identical

>>> globals() is locals()
True

but inside a function they are distinct

>>> def f(): return globals() is locals()
... 
>>> f()
False

A workaround is to declare "math" as global:

>>> s = """
... global math
... import math
... def f(y): print math.floor(y)
... f(3.14)
... """
>>> def execute():
...     exec s
... 
>>> execute()
3.0

or pass it explicitly:

[new interpreter session]
>>> s = """
... import math
... def f(y, math=math): print math.floor(y)
... f(3.14)
... """
>>> def execute():
...     exec s
... 
>>> execute()
3.0

Peter



More information about the Python-list mailing list