Why does the following python3 code produces an error?
a='''
def x():
print(42)
'''
class Test:
def __init__(self):
exec(a)
x()
t = Test()
Results in this message:
Traceback (most recent call last):
File "bug.py", line 11, in <module>
t = Test()
File "bug.py", line 9, in __init__
x()
NameError: global name 'x' is not defined
I am assuming you are using Python3.x, since in Python2.7, your code is working fine for me. So for Python3.x, change the line
to
in order to add
x
to the global namespace.Documentation
Python3
exec
also takesglobals
andlocals
optional arguments of mapping type, which act as a context for the given code execution:By default the local scope gets passed in for both. The executed code can use it, can also modify the dict, but it will have no effect on the actual local scope. See
locals()
and example:Output:
If you want the
x
to be available after theexec
call you either need to pass in a global or a custom scope:Note:
exec
was just a Simple statement in Python 2.x, whereas it is a function in Python 3.x.Python 2.7
Let us check the changes made by executing
a
.Output
It means that, it has changed something in the
locals
dictionary. If you printlocals().keys()
before and after theexec
, you will seex
, afterexec
. As per the documentation of exex,So, it does exactly what the documentation says.
Python 3.x:
When we execute the same in Python 3.x, we get similar result, except we get that error.
Output
Even the documentation of
exec
function says,But it also includes a note at the bottom,
So, we curiously check the
locals()
documentation and findSo, interpreter doesn't honor the changes made to the
locals()
object. That is why it is not recognizingx
as defined in the local scope.But when we do
it works, because we add it to the
globals
dictionary. Python tries to findx
in local scope first and then in class scope and then in global scope and it finds it there. So it executes it without any problem.