This is a pretty 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 this doesn't work is because the subfunction contains a free variable, and since in Python 2, exec could theoretically modify locales in the content area, it would be impossible to decide whether the variable should be associated with a global or parent function. One of the poems in Zen Python is "In the face of ambiguity, give up the temptation to guess." and this is what Python 2 does.
Now the question is: what is this unrelated variable? Well, that’s True !
Indeed, it is played using 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 if None cannot be assigned, and it is considered a constant in the bytecode, the buggy parser considers this to be an unrelated 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 global and possibly local that exec will use, say:
>>> def test2(): ... exec 'print "hi from test2"' in {} ... def subfunction(): ... return None ... >>>
In Python 3, exec is just a simple function and is not specifically handled by the parser or bytecode compiler. In Python 3, exec cannot restore function-local names, and thus this syntaxError and ambiguity do not exist.
One of the special cases of Python 2 vs 3 compatibility is that while the Python 2.7 Documentation states that
The form exec(expr, globals) equivalent to exec expr in globals , and the form exec(expr, globals, locals) equivalent to exec expr in globals, locals . The exec tuple form provides compatibility with Python 3, where exec is a function, not an operator.
The tuple form was not always 100% compatible, since there was an error processing exec in functions with nested functions (number 21591) ; up to Python 2.7.8, the following code may throw an exception:
def func(): exec('print "hi from test2"', {}) def subfunction(): return None
This has been fixed in Python 2.7.9 and it no longer throws.