exec()
exec(object, globals=None, locals=None) Returns:
None · Added in v3.0 · Updated March 13, 2026 · Built-in Functions dynamic execution code built-in security
The exec() function executes dynamically created Python code provided as a string or compiled code object. Unlike eval() which only evaluates expressions and returns a value, exec() executes complete Python statements including assignments, loops, function definitions, and class definitions. It returns None.
Syntax
exec(object, globals=None, locals=None)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
object | str or code | — | A string containing Python statements or a compiled code object |
globals | dict or None | None | Dictionary providing global namespace for code execution |
locals | dict or None | None | Dictionary providing local namespace for code execution |
Examples
Basic code execution
code = "print('Hello from exec!')"
exec(code)
# Hello from exec!
Executing statements with variables
code = """x = 5
y = 10
result = x + y
print(f'Sum: {result}')"""
exec(code)
# Sum: 15
Using globals and locals
my_globals = {"width": 100}
my_locals = {"height": 50}
code = "area = width * height"
exec(code, my_globals, my_locals)
print(my_locals.get("area"))
# 5000
Executing compiled code
# Pre-compile code for repeated execution
compiled = compile("""for i in range(3):
print(f'Iteration {i}')""", "dynamic_code", "exec")
exec(compiled)
# Iteration 0
# Iteration 1
# Iteration 2
Defining functions dynamically
code = """def greet(name):
return f'Hello, {name}!'"""
exec(code)
# Function is now available in the current scope
result = greet("World")
print(result)
# Hello, World!
Common Patterns
Configuration file evaluation
def load_config(config_string):
"""Load configuration from a Python-like syntax string."""
config = {}
exec(config_string, {}, config)
return config
config_str = """database = 'production'
max_connections = 100
timeout = 30"""
settings = load_config(config_str)
print(settings)
# {'database': 'production', 'max_connections': 100, 'timeout': 30}
Template engine simulation
def render_template(template, context):
"""Simple template rendering using exec."""
code = f'result = f"""{template}"""'
exec(code, {}, {**context, "result": None})
return context.get("result", "")
template = "Hello, {name}! You have {count} messages."
result = render_template(template, {"name": "Alice", "count": 5})
print(result)
# Hello, Alice! You have 5 messages.
DSL implementation
def execute_commands(commands):
"""Execute a simple domain-specific language."""
context = {"variables": {}}
for cmd in commands:
if cmd.startswith("set "):
_, var, val = cmd.split(" ", 2)
context["variables"][var] = val
elif cmd.startswith("print "):
_, var = cmd.split(" ", 1)
print(context["variables"].get(var, ""))
else:
exec(cmd, {}, context["variables"])
commands = [
"set x 10",
"set y 20",
"print x + y"
]
execute_commands(commands)
# 30
Security Considerations
⚠️ CRITICAL: exec() is extremely dangerous. Never use it with untrusted input.
Why exec() is risky
# UNSAFE - Never do this!
user_code = input("Enter code: ")
exec(user_code)
# A malicious user could enter:
# __import__('os').system('rm -rf *')
# Or:
# for f in __import__('os').listdir('.'):
# __import__('os').remove(f)
What attackers can do
With unrestricted exec() access, an attacker can:
- Read, modify, or delete any file on the system
- Execute shell commands
- Access environment variables and secrets
- Import any module and use its capabilities
- Escalate privileges
- Exfiltrate data
Mitigation strategies
- Never exec() user-provided strings — treat all input as potentially malicious
- Restrict the globals namespace — never pass
Noneas globals; use an empty or heavily restricted dict - Remove dangerous builtins — filter out
__import__,open,eval,exec,system, etc. - Use separate processes — run untrusted code in isolated processes with limited permissions
- Consider alternatives — most use cases for
exec()have safer alternatives
Restricted execution example
def safe_exec(code):
"""Execute code with restricted globals."""
# Create a safe globals dict with minimal builtins
safe_globals = {
"__builtins__": {
"print": print,
"len": len,
"range": range,
"str": str,
"int": int,
"float": float,
"list": list,
"dict": dict,
"tuple": tuple,
"set": set,
"bool": bool,
"abs": abs,
"min": min,
"max": max,
"sum": sum,
"sorted": sorted,
"enumerate": enumerate,
"zip": zip,
"map": map,
"filter": filter,
}
}
safe_locals = {}
exec(code, safe_globals, safe_locals)
return safe_locals
# This works
safe_exec("x = [1, 2, 3]; print(len(x))")
# 3
# This fails - dangerous functions not available
# safe_exec("__import__('os').system('ls')")
# NameError: __import__ is not defined
Errors
| Error | When |
|---|---|
SyntaxError | Code has invalid Python syntax |
NameError | Code references an undefined name |
TypeError | Wrong argument types passed to exec() |
AttributeError | Code tries to access unavailable attributes |
SecurityError | (Custom) Code attempts forbidden operations |
See Also
- built-in::eval — evaluate Python expressions (returns a value)
- built-in::compile — pre-compile code objects for repeated execution
- Python execution model docs — background on Python statements and execution context