Python Python exec(): Execute dynamic code — syntax, globals and locals, stat…
page info
name Goposu datetime⏰ 25-10-11 17:44 hit👁️ 20 comment💬 0text

Python exec(): Run dynamically generated Python code
exec()
executes Python statements from a string or compiled code object. Unlike eval()
, which evaluates an expression and returns a value, exec()
can run blocks of code including assignments, function/class definitions, loops, and imports. This flexibility is powerful but risky if inputs aren’t trusted; use strict scoping and whitelisting.
Syntax
exec(source, globals=None, locals=None)
- source: A string of Python code or a compiled code object.
- globals: Optional dictionary for the global namespace used during execution.
- locals: Optional dictionary for the local namespace used during execution.
Quick examples
# Define variables and functionscode = """x = 2y = 3def add(a, b):return a + bz = add(x, y)"""ns = {}exec(code, ns)print(ns["z"]) # 5print(ns["add"](10, 20)) # 30
Globals and locals
exec()
resolves names via globals
and locals
. If omitted, the current scope (including built-ins) is used. To control effects and limit access, pass explicit dicts and consider removing built-ins.
# Restrict the environmentsafe_globals = {"__builtins__": {}} # remove built-inssafe_locals = {}exec("a = 10\nb = 20\nc = a + b", safe_globals, safe_locals)print(safe_locals["c"]) # 30
Statements vs expressions
- exec(): Runs statements (assignments, defs, loops, imports). Returns None.
- eval(): Evaluates a single expression and returns its value.
# exec can define functions and classesexec("""class Greeter:def hello(self):return 'hi'""")print(Greeter().hello()) # hi
compile() modes and precompilation
Use compile()
to pre-parse code, validate its type, and reuse efficiently. Modes: "exec"
for statements, "eval"
for expressions, "single"
for a single interactive statement.
# Pre-compile a statement blocksrc = "total = sum(range(5))"code_obj = compile(src, filename="", mode="exec")
scope = {"builtins": {}} exec(code_obj, scope) print(scope["total"]) # 10
Compile a single interactive statement
stmt = compile("print('hello')", "", "single") exec(stmt)
Security risks and sandboxing
- Arbitrary code execution: Untrusted input can import modules, read/write files, or execute system calls.
- Built-ins exposure: Without restrictions, dangerous functions (e.g.,
__import__
) are available. - Mitigation: Remove built-ins, whitelist allowed functions/modules, and validate code (regex/AST). Consider running in isolated processes.
# Whitelist-only environmentimport mathenv = {"__builtins__": {}, # remove all built-ins"math": math, # allow math only}user_code = "result = math.sqrt(49)"exec(user_code, env)print(env["result"]) # 7.0
Common patterns
- Dynamic function creation: Generate small utilities or formulas at runtime.
- Configuration-driven scripts: Execute trusted admin-authored blocks with a limited namespace.
- Educational/repl tools: Run code snippets with timeouts and sandboxing.
# Build a function from a templatetmpl = """def f(x, y):return x {op} y"""ns = {}exec(tmpl.format(op="*"), ns)print(ns["f"](6, 7)) # 42
Pitfalls and how to avoid them
- Silent failures:
exec()
returns None; inspect namespaces for results. - State leaks: Running in the current scope can mutate globals; prefer isolated dicts.
- Debuggability: Generated code obscures stack traces; set meaningful
filename
incompile()
. - Performance: Repeatedly parsing strings is expensive; pre-compile for reuse.
Practical examples
# 1) Execute a trusted setup scriptsetup = '''threshold = 0.8def score(x):return x * 100'''conf = {"__builtins__": {}}exec(setup, conf)print(conf["threshold"], conf["score"](0.9)) # 0.8 90.0
2) Evaluate per-request formulas with compile()
formula = compile("out = base * (1 + rate)", "", "exec") ns = {"builtins": {}, "base": 100, "rate": 0.25} exec(formula, ns) print(ns["out"]) # 125.0
3) Capture output safely (provide print)
def safe_print(*args, **kwargs): pass # no-op or custom logger env = {"builtins": {}, "print": safe_print} exec("print('This will be logged')", env)
FAQ
- Can exec() return a value?
- No. It executes statements and returns None. Store results in the provided namespace dict and read them after.
- How do I limit what exec() can access?
- Provide custom
globals
/locals
, set__builtins__
to an empty dict, and expose only whitelisted functions/modules. - Should I use exec() for user input?
- Generally no. Use parsers, domain-specific languages, or vetted whitelists; consider isolated processes for untrusted code.
Related keywords
Python exec, dynamic code execution, globals locals, sandbox, compile modes, security, whitelist, code generation, statements vs expressions
comment list 0
There are no registered comments.