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

ParameterTypeDefaultDescription
objectstr or codeA string containing Python statements or a compiled code object
globalsdict or NoneNoneDictionary providing global namespace for code execution
localsdict or NoneNoneDictionary 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

  1. Never exec() user-provided strings — treat all input as potentially malicious
  2. Restrict the globals namespace — never pass None as globals; use an empty or heavily restricted dict
  3. Remove dangerous builtins — filter out __import__, open, eval, exec, system, etc.
  4. Use separate processes — run untrusted code in isolated processes with limited permissions
  5. 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

ErrorWhen
SyntaxErrorCode has invalid Python syntax
NameErrorCode references an undefined name
TypeErrorWrong argument types passed to exec()
AttributeErrorCode tries to access unavailable attributes
SecurityError(Custom) Code attempts forbidden operations

See Also