Dynamic Execution: eval, exec, & compile
Most programs are static: the code you write is the code that runs. However, Python is dynamic enough to create and execute code at runtime. This is extremely powerful for building things like template engines, math expression parsers, or plugin systems.
But with great power comes extreme danger—improper use of dynamic execution is the leading cause of security vulnerabilities.
1. eval(): Expression Evaluator
Section titled “1. eval(): Expression Evaluator”eval(expression) parses a single Python expression, executes it, and returns the result.
x = 10result = eval("x * 5 + 2")print(result) # Output: 52Constraint: eval() cannot handle statements like if, for, or assignments (x = 5). It only works for things that return a value.
2. exec(): Block Executor
Section titled “2. exec(): Block Executor”exec(code) can handle complex blocks of Python code, including function definitions, loops, and classes. It always returns None.
logic = """for i in range(3): print(f"Cycle {i}")"""exec(logic)3. Sandboxing: The globals and locals Args
Section titled “3. Sandboxing: The globals and locals Args”By default, eval and exec have access to all your variables and built-in functions (including os.system, which can delete your hard drive!). To make it safer, you should pass custom dictionaries.
# Restrict access to ONLY the 'math' library and a few variablessafe_scope = { "__builtins__": {}, # Disable all built-in functions (print, open, etc.) "x": 10}
# result = eval("open('passwords.txt').read()", safe_scope) # Raises NameError4. Under the Hood: compile()
Section titled “4. Under the Hood: compile()”When you call exec("print(1)"), Python has to:
- Parse the string into an AST.
- Compile the AST into Bytecode.
- Run the Bytecode.
If you are running the same string multiple times (e.g., in a loop), this is very slow. You can pre-compile the string using compile().
source = "x += 1"# Compile into a 'code object'byte_code = compile(source, filename="<string>", mode="exec")
context = {"x": 0}for _ in range(1000): exec(byte_code, context)
print(context["x"]) # 10005. Security Warning (CRITICAL)
Section titled “5. Security Warning (CRITICAL)”Even with sandboxing, a clever attacker can often break out of the scope using introspection (e.g., accessing ().__class__.__base__). If you need to evaluate mathematical expressions from users, use a dedicated library like simpleeval or a formal parser.
6. Summary Table
Section titled “6. Summary Table”| Tool | Input | Output | Best Use Case |
|---|---|---|---|
eval() | Expression string. | The result value. | Simple math/logic parsers. |
exec() | Block of code. | None. | Dynamic plugins or class creation. |
compile() | String code. | Code object. | Performance optimization for loops. |
ast.literal_eval() | Constant string. | Python literal. | The safe way to parse strings into dicts/lists. |