Why doesn't exec work in a function with a subfunction?
It looks like you can't use exec in a function that has a subfunction...
Anyone know why this Python code doesn't work? I get an error at the exec in test2. Also, I know exec's aren't good style, but trust me, I'm using exec for an appropriate reason. I wouldn't use it otherwise.
#!/usr/bin/env python
#
def test1():
exec('print "hi from test1"')
test1()
def test2():
"""Test with a subfunction."""
exec('print "hi from test2"')
def subfunction():
return True
test2()
EDIT: I narrowed down the bug to having a function in a subfunction. It has nothing to do with the raise keyword.
Correct. You can't use exec in a function that has a subfunction, unless you specify a context. From the docs:
If exec is used in a function and the function contains a nested block with free variables, the compiler will raise a SyntaxError unless the exec explicitly specifies the local namespace for the exec. (In other words, "exec obj" would be illegal, but "exec obj in ns" would be legal.)
There is good reason for this which I would probably understand if it wasn't Sunday night. Now, next question: Why are you using exec? It's very rarely needed. You say you have a good reason. I'm feeling sceptical about that. ;) If you have a good reason I'll tell you the workaround. :-P
Oh well, here it is anyway:
def test2():
"""Test with a subfunction."""
exec 'print "hi from test2"' in globals(), locals()
def subfunction():
return True
Although in Python it looks kind of like the local variables are stored in a dictionary locals()
, they usually aren't. Instead they are mostly stored on the stack and accessed by index. This makes local variable lookup faster than if it had to do a dictionary lookup every time. If you use the locals()
function then what you get is a fresh dictionary created from all the local variables, and that's why assigning to locals()
doesn't generally work.
There are a couple of exceptions to this scenario:
When you use an unqualified exec
inside a function Python turns off the optimisation and uses a real dictionary for the local variables. That means you can create or update variables from inside the exec
, but it also means all local variable access in that function will run more slowly.
The other exception is that when you nest functions the inner function can access local variables in the outer function scope. When it does this the variable is stored in a 'cell' object instead of being stored on the stack. The extra level of indirection makes all use of scoped variables slower whether you access them from the inner or outer function.
The catch that you've encountered is that these two exceptions to how local variables are normally stored are incompatible. You cannot have a variable stored in a dictionary and accessed through a cell reference at the same time. Python 2.x fixes this by disallowing the exec, even in cases like this where you aren't trying to use any scoped variables.
This is a rather interesting case:
>>> def func():
... exec('print "hi from func"')
... def subfunction():
... return True
...
File "<stdin>", line 2
SyntaxError: unqualified exec is not allowed in function 'func' because
it contains a nested function with free variables
The reason why this doesn't work indeed is that subfunction
contains a free variable, and since in Python 2, exec
could theoretically modify the locals in the containing scope, it would be impossible to decide if the variable should be bound from the global or the parent function scope. One of the verses in the Zen of Python is "In the face of ambiguity, refuse the temptation to guess." and this is what Python 2 does.
Now the question is: what is this free (unbound) variable? Well, it is True
!
Indeed it is reproduceable with None
:
>>> def func():
... exec('print "hi from func"')
... def subfunction():
... return None
...
File "<stdin>", line 2
SyntaxError: unqualified exec is not allowed in function 'test2' because it contains a nested
function with free variables
Even though None
cannot be assigned to, and it is considered as a constant in the bytecode, the buggy parser thinks it is an unbound variable here.
But if you replace it with 1
and it works without problems:
>>> def test2():
... exec('print "hi from func"')
... def subfunction():
... return 1
...
>>>
To avoid this error, specify explicitly the globals and possibly locals that are to be used by exec
, say:
>>> def test2():
... exec 'print "hi from test2"' in {}
... def subfunction():
... return None
...
>>>
In Python 3, exec
is just a simple function and isn't handled specially by the parser or the bytecode compiler. In Python 3 exec
cannot rebind function-local names, and thus this SyntaxError and ambiguity doesn't exist.
One peculiar case in Python 2 vs 3 compatibility is that while Python 2.7 documentation states that
The form
exec(expr, globals)
is equivalent toexec expr in globals
, while the formexec(expr, globals, locals)
is equivalent toexec expr in globals, locals
. The tuple form ofexec
provides compatibility with Python 3, whereexec
is a function rather than a statement.
The tuple form has not always been 100 % compatible, as there was a bug in handling of exec
in functions with nested functions (issue 21591); up to Python 2.7.8 the following code might have thrown an exception:
def func():
exec('print "hi from test2"', {})
def subfunction():
return None
This was fixed in Python 2.7.9 and it no longer throws.
That works well in Python 3.1.3, after modifying the print statement to use print function.
In Python 2.6, it produces SyntaxError: unqualified exec is not allowed in function 'test2' it contains a nested function with free variables
, I don't think it's a bug.