Why Doesn't Exec Work in a Function with a Subfunction

Why doesn't exec work in a function with a subfunction?

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

Workaround for subfunction defined in exec() inside of a function

There's no need to create the function dynamically and use exec. Just iterate over xdat.

def fitFunc(xdat, a, b):
return (a/ps) * sum(x**b for x in xdat)

Exec doesn't work with functions and variables

Let me give a simple example of what I was telling you in the comments. This is my folder structure:

/sample
- plugins/
- __init__.py # not necessary, but maybe you want to apply some logic
# before importing the plugins
- plugin1.py
- plugin2.py
- plugin3.py
- __init__.py
- test.py

Every plugin prints what plugins it is (e.g., print('plugin 1')). test.py is as follows:

import os

if __name__ == '__main__':
# load plugins
plugins = [p for p in os.listdir('plugins') if not p.startswith('_')]
for p in plugins:
__import__('plugins.'+p[:-3])

The output is:

plugin 1
plugin 2
plugin 3

Which means I successfully imported all those modules (plugins) by using __import__. Note that __import__ returns a reference to the imported module, so you can store it for later manipulation. Hope it helps!

Why am I getting errors with execs nested in functions?

The answer, as said in this question, is the lack of context. I wanted exec code in locals(), globals()

Exec in Python 2.7.6

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 (namespace)" would be
legal.)

Here is the code to implement exec:

def test2():
"""Test with a subfunction."""
exec 'print "hi from test2"' in globals(), locals()
def subfunction():
return True

test2()

This example was taken from: In Python, why doesn't exec work in a function with a subfunction?

Why doesn't exec(break) work inside a while loop

This is because exec() is ignorant to your surrounding while loop. So the only statement that exec() sees in your example is break. Instead of using exec("break"), simply use break as is.

The only access the exec() function has to its surrounding scope, is the globals() and locals() dictionaries. The documentation for exec() provides some insight into how exec() works:

This function supports dynamic execution of Python code. object must be either a string or a code object. If it is a string, the string is parsed as a suite of Python statements which is then executed (unless a syntax error occurs). [1] If it is a code object, it is simply executed. In all cases, the code that’s executed is expected to be valid as file input (see the section “File input” in the Reference Manual). Be aware that the return and yield statements may not be used outside of function definitions even within the context of code passed to the exec() function. The return value is None.

In all cases, if the optional parts are omitted, the code is executed in the current scope. If only globals is provided, it must be a dictionary, which will be used for both the global and the local variables. If globals and locals are given, they are used for the global and local variables, respectively. If provided, locals can be any mapping object. Remember that at module level, globals and locals are the same dictionary. If exec gets two separate objects as globals and locals, the code will be executed as if it were embedded in a class definition.

If the globals dictionary does not contain a value for the key builtins, a reference to the dictionary of the built-in module builtins is inserted under that key. That way you can control what builtins are available to the executed code by inserting your own builtins dictionary into globals before passing it to exec().

Python problem with function declaration inside exec

TLDR: Provide explicit globals dictionaries to execute code "as if" it were run at top-level.


Python uses lexical scoping, which roughly means that names are looked up as per the nesting in source code. For example, a nested function can access an outer function's variable.

def foo():
bar = 12
def qux():
print(bar) # nested scope accesses outer scope
return qux

Notably, this kind of name lookup happens at source code compilation time – the compiler knows that both foo and qux access bar, so it must be made available to both. The inner function is directly compiled to look at the variable of the outer function.

If instead a function is not nested, its name lookup to non-local variables automatically goes to global scope.

def qux():
print(bar) # top-level scope accesses global scope

This is a problem when we exec code in a function: A definition such as def main(): this() is compiled to lookup this at global scope, but exec runs in the current local scope of the function.

In all cases, if the optional parts are omitted, the code is executed in the current scope.

Thus, this is looked up globally but defined locally.1 The compiler parses def test and the exec code separately, so it does not know that lookups are meant to be treated as nested.

As a result, the lookup fails.

In order to exec code "as if" it were run at top-level, it is sufficient to supply an explicit globals – for example a fresh namespace {} or the actual globals().

def test():
exec("""
def this():
print('this')

def main():
this()

main()
""", {})
# ^^ globals namespace for exec

test()

This means the code is now run in (its own) global namespace, which is where the lookup of functions searches as well.


1This can be checked by printing globals()/locals() and by inspecting the instructions of the function. dis.dis(main) in the exec would produce:

  6           0 LOAD_GLOBAL              0 (this)
2 CALL_FUNCTION 0
4 POP_TOP
6 LOAD_CONST 0 (None)
8 RETURN_VALUE

exec() not working inside function python3.x

Instead of using exec with function names, just keep the function objects in the list:

fn_lst = [has_at, has_num, ...]

and perform the call directly:

def abc(xyz):
for i in fn_lst:
temp= i(xyz)
print(temp)

Why doesn't an import in an exec in a function work?

How about this:

def test():
exec (code, globals())
f()


Related Topics



Leave a reply



Submit