- 5.1 Function Definitions
- 5.2 Default Arguments
- 5.3 Variadic Arguments
- 5.4 Keyword Arguments
- 5.5 Variadic Keyword Arguments
- 5.6 Functions Accepting All Inputs
- 5.7 Positional-Only Arguments
- 5.8 Names, Documentation Strings, and Type Hints
- 5.9 Function Application and Parameter Passing
- 5.10 Return Values
- 5.11 Error Handling
- 5.12 Scoping Rules
- 5.13 Recursion
- 5.14 The lambda Expression
- 5.15 Higher-Order Functions
- 5.16 Argument Passing in Callback Functions
- 5.17 Returning Results from Callbacks
- 5.18 Decorators
- 5.19 Map, Filter, and Reduce
- 5.20 Function Introspection, Attributes, and Signatures
- 5.21 Environment Inspection
- 5.22 Dynamic Code Execution and Creation
- 5.23 Asynchronous Functions and await
- 5.24 Final Words: Thoughts on Functions and Composition
5.22 Dynamic Code Execution and Creation
The exec(str [, globals [, locals]]) function executes a string containing arbitrary Python code. The code supplied to exec() is executed as if the code actually appeared in place of the exec operation. Here’s an example:
a = [3, 5, 10, 13] exec('for i in a: print(i)')
The code given to exec() executes within the local and global namespace of the caller. However, be aware that changes to local variables have no effect. For example:
def func(): x = 10 exec("x = 20") print(x) # Prints 10
The reasons for this have to do with the locals being a dictionary of collected local variables, not the actual local variables (see the previous section for more detail).
Optionally, exec() can accept one or two dictionary objects that serve as the global and local namespaces for the code to be executed, respectively. Here’s an example:
globs = {'x': 7, 'y': 10, 'birds': ['Parrot', 'Swallow', 'Albatross'] } locs = { } # Execute using the above dictionaries as the global and local namespace exec('z = 3 * x + 4 * y', globs, locs) exec('for b in birds: print(b)', globs, locs)
If you omit one or both namespaces, the current values of the global and local namespaces are used. If you only provide a dictionary for globals, it’s used for both the globals and locals.
A common use of dynamic code execution is for creating functions and methods. For example, here’s a function that creates an __init__() method for a class given a list of names:
def make_init(*names): parms = ','.join(names) code = f'def __init__(self, {parms}):\n' for name in names: code += f' self.{name} = {name}\n' d = { } exec(code, d) return d['__init__'] # Example use class Vector: __init__ = make_init('x','y','z')
This technique is used in various parts of the standard library. For example, namedtuple(), @dataclass, and similar features all rely on dynamic code creation with exec().