Python exec()

Python exec() is a powerful function for dynamically executing code at runtime. It is useful for dynamic code generation, scripting, and other advanced tasks. However, it should be used with caution due to potential security risks.
Table of Contents

Understanding Python exec() Function

Python exec() is a built-in function that executes dynamically created Python code. Unlike eval(), used for evaluating expressions, exec() is designed to execute statements or even entire blocks of code represented as strings or code objects. This function provides a powerful way to run code you might not know when writing the program, such as code generated at runtime or fetched from external sources. Python exec() is more powerful than the eval() function.

Syntax of Python exec()

result = exec(object, globals, locals)

Explanation

  • result: Variable will always be None as exec() function does not return any value.
  • exec(): Built-in function that executes the code.
  • object: Either a string containing Python code or a code object. It is the main parameter for exec() function.
  • globals (optional): Dictionary specifying the global namespace for the code execution.
  • locals (optional): Dictionary specifying the local namespace for the code execution.

Example of Python exec()

code_string = "print('Hello, world!')"
exec(code_string)

Explanation

  • code_string = "print('Hello, world!')": Creates a string code_string that contains a simple Python print statement.
  • exec(code_string): Executes the code in code_string using exec().

Output

Hello, world!


exec() Parameters

Python exec() function takes up to three parameters: object, globals, and locals. The object parameter is the code you want to execute, which can be a string or a compiled code object. The globals parameter is an optional dictionary that provides a global namespace for the code execution; if omitted, the current global namespace is used. The locals parameter is another optional dictionary for the local namespace; if omitted, it defaults to the value of globals. You can pass a single dictionary for globals and skip locals parameter; in this case, globals will be used for both global and local namespace.

Syntax

exec(object, globals, locals)

Explanation

  • exec(): Function that executes the dynamic code.
  • object: Either a string containing Python code or a code object to be executed. It is the main parameter for exec() function.
  • globals (optional): Dictionary representing the global namespace. It is the second parameter for exec().
  • locals (optional): Dictionary representing the local namespace. It is the third parameter for exec()..

Example

code = "x = 5\ny = 10\nprint(x + y)"
global_vars = {}
local_vars = {}
exec(code, global_vars, local_vars)

Explanation

  • code = "x = 5\ny = 10\nprint(x + y)": Creates a multi-line string code containing Python code.
  • global_vars = {}: Initializes an empty dictionary global_vars to be used as the global namespace.
  • local_vars = {}: Initializes an empty dictionary local_vars to be used as the local namespace.
  • exec(code, global_vars, local_vars): Executes the code in code using the specified global_vars and local_vars for the global and local namespaces.

Output

15


exec() Return Value

Python exec() function always returns None. Unlike eval(), which returns the result of an expression, exec() is designed for executing statements and code blocks that don’t necessarily produce a value. The primary purpose of exec() is to perform actions, modify variables, define functions, or execute any other Python code dynamically, not to compute and return a specific value.

Syntax

return_value = exec(code)

Explanation

  • return_value: Variable will always be None because exec() does not return anything else.
  • exec(): Function executes the code in code but does not return any value.
  • code: String or code object to be executed. It is used as input for exec() function.

Example

result = exec("a = 5")
print(result)

Explanation

  • result = exec("a = 5"): Executes the code string “a = 5” using exec(), which assigns 5 to a in the current namespace but returns None.
  • print(result): Prints the value of result, which is None.

Output

None


exec() With a Single Line Program Input

You can use Python exec() to execute a single line of Python code represented as a string. This can be handy for quickly running a simple statement generated or modified at runtime. The single line of code can be an assignment, a function call, or any other valid Python statement. You must pass a single-line statement as a string to the object parameter.

Syntax

exec(single_line_code_string)

Explanation

  • exec(): Function executes the single line of code.
  • single_line_code_string: String containing a single line of Python code. It is passed as input to exec() function.

Example

exec("b = 10")
print(b)

Explanation

  • exec("b = 10"): Executes the code string “b = 10”, which assigns the value 10 to the variable b.
  • print(b): Prints the value of b, which is now 10.

Output

10


exec() with a Multi-line Input Program

Python exec() function can handle multi-line strings as input, allowing you to dynamically execute entire blocks of code. This is useful for running scripts or code snippets generated at runtime or loaded from external sources. To use multi-line input, create a string that contains multiple lines of Python code, separated by newline characters (\n), and pass it to exec().

Syntax

exec(multi_line_code_string)

Explanation

  • exec(): Function executes the multi-line code string.
  • multi_line_code_string: String containing multiple lines of Python code, separated by newline characters. It is used as input for exec() function.

Example

code = """
c = 7
d = 3
result = c * d
print(result)
"""
exec(code)

Explanation

  • code = """...""": Creates a multi-line string code containing Python code that defines variables and performs a calculation.
  • exec(code): Executes the multi-line code string using exec().

Output

21


Checking Usable Code with exec()

Before executing dynamically generated or loaded code with Python exec(), it’s often a good idea to check if the code is valid and safe to run. One basic check is to use compile() to try to compile the code string into a code object. If the code is syntactically incorrect, compile() will raise an exception, allowing you to catch the error before executing the code with exec().

Syntax

try:
    code_object = compile(code_string, '<string>', 'exec')
    exec(code_object)
except SyntaxError:
    # Handle syntax error

Explanation

  • try:: Block attempts to compile and execute the code.
  • code_object = compile(code_string, '<string>', 'exec'): Tries to compile code_string into a code object.
  • exec(code_object): Executes the compiled code object if compilation is successful.
  • except SyntaxError:: Block catches a SyntaxError if one occurs during compilation.
  • # Handle syntax error: Where you would write code to handle syntax errors.

Example

code_string = "print('Hello, world')"  # Missing colon to cause a SyntaxError

try:
    code_object = compile(code_string, "<string>", "exec")
    exec(code_object)
except SyntaxError as e:
    print(f"Syntax error: {e}")

Explanation

  • code_string = "print('Hello, world')": Creates a string code_string with a syntax error (missing colon).
  • try:: Block attempts to compile and execute the code.
  • code_object = compile(code_string, "<string>", "exec"): Attempts to compile code_string, which will raise a SyntaxError.
  • exec(code_object): Execute the code if it were valid.
  • except SyntaxError as e:: Block catches the SyntaxError.
  • print(f"Syntax error: {e}"): Prints an error message.

Output

Syntax error: invalid syntax (<string>, line 1)


Blocking Unnecessary Methods and Variables in exec()

When using Python exec(), you can enhance security and control by blocking unnecessary methods and variables from being accessed within the executed code. You do this by providing custom globals and locals dictionaries that don’t include the names you want to block. This prevents the dynamically executed code from interacting with parts of your program that it shouldn’t have access to.

Syntax

globals_dict = {‘__builtins__’: None} # Block built-in functions and variables
locals_dict = {}
exec(code_string, globals_dict, locals_dict)

Explanation

  • globals_dict: Dictionary defines the global namespace for the executed code.
  • {'__builtins__': None}: Disables access to built-in functions and variables by setting __builtins__ to None.
  • locals_dict: Dictionary defines the local namespace for the executed code.
  • exec(): Function executes code_string with the specified globals_dict and locals_dict.
  • code_string: Code to be executed. It is used as input for exec().

Example

code = "print(len([1, 2, 3]))"  # Attempt to use built-in len()
safe_globals = {'__builtins__': None}
safe_locals = {}

try:
    exec(code, safe_globals, safe_locals)
except NameError as e:
    print(f"Error: {e}")

Explanation

  • code = "print(len([1, 2, 3]))": Code string attempts to use the built-in functions print and len.
  • safe_globals = {'__builtins__': None}: Creates a globals dictionary that blocks access to built-ins.
  • safe_locals = {}: Creates an empty locals dictionary.
  • try:: Block attempts to execute the code with restricted access.
  • exec(code, safe_globals, safe_locals): Executes code with the restricted namespaces, which will raise a NameError.
  • except NameError as e:: Block catches the NameError.
  • print(f"Error: {e}"): Prints the error message.

Output

Error: name ‘print’ is not defined


Using Necessary Methods and Variables in exec()

While it’s often important to restrict access when using Python exec(), you can also selectively allow certain methods and variables to be used within the dynamically executed code. You do this by including them in the globals and/or locals dictionaries that you pass to exec(). This way, you can provide the executed code with the specific tools it needs while maintaining control over the execution environment.

Syntax

globals_dict = {‘allowed_variable’: some_value, ‘allowed_function’: some_function}
locals_dict = {}
exec(code_string, globals_dict, locals_dict)

Explanation

  • globals_dict: Dictionary defines the global namespace, including any allowed variables or functions.
  • {'allowed_variable': some_value, 'allowed_function': some_function}: Adds specific variables and functions to the global namespace.
  • locals_dict: Dictionary defines the local namespace (can be empty if you only want to allow globals).
  • exec(): Function executes code_string with the specified globals_dict and locals_dict.
  • code_string: Code to be executed, which can now use the allowed names. It is used as input for exec().

Example

def safe_power(a, b):
    return a ** b

code = "result = safe_power(2, 3)\nprint(result)"
globals_dict = {'safe_power': safe_power}
locals_dict = {}

exec(code, globals_dict, locals_dict)

Explanation

  • def safe_power(a, b):: Defines a function safe_power that’s allowed to be used in the exec() call.
  • return a ** b: Returns a raised to the power of b.
  • code = "result = safe_power(2, 3)\nprint(result)": Code string uses the allowed safe_power function.
  • globals_dict = {'safe_power': safe_power}: Creates a globals dictionary that includes only safe_power.
  • locals_dict = {}: Creates an empty locals dictionary.
  • exec(code, globals_dict, locals_dict): Executes code with access to safe_power but no other globals or locals.

Output

8


Dynamic Code Generation

One of the most powerful Python exec() applications is dynamic code generation. This involves creating strings of Python code at runtime, often based on user input, data from files, or other programmatic logic. Once the code string is generated, you can use exec() to execute it. This technique allows you to create highly flexible programs that adapt their behavior based on changing conditions or requirements.

Syntax

dynamically_generated_code = generate_code(some_input)
exec(dynamically_generated_code)

Explanation

  • dynamically_generated_code: Variable will hold the string of Python code generated at runtime.
  • generate_code(some_input): Represents a function that creates a code string based on some_input.
  • exec(): Function executes the dynamically generated code.
  • dynamically_generated_code: Code string to be executed. It is passed as input to exec().

Example

def generate_code(number):
    return f"print({number} * 2)"

code_to_execute = generate_code(5)
exec(code_to_execute)

Explanation

  • def generate_code(number):: Defines a function generate_code that creates a code string.
  • return f"print({number} * 2)": Returns a string that, when executed, will print twice the input number.
  • code_to_execute = generate_code(5): Calls generate_code to create a code string for the number 5.
  • exec(code_to_execute): Executes the generated code string using exec().

Output

10


Warning or Limitations

While Python exec() is powerful, it has significant limitations and security implications. The primary concern is that executing arbitrary code strings, especially from untrusted sources, can introduce severe security vulnerabilities. Malicious code could be injected and executed, potentially harming your system or data. Additionally, exec() can make debugging harder, as the executed code is not directly part of your source file. It’s generally recommended to use safer alternatives to exec() when possible and to carefully validate and sanitize any external input before executing it.

Syntax

exec(untrusted_code_string) # Potentially unsafe

Explanation

  • exec(): Function executes the code in untrusted_code_string.
  • untrusted_code_string: Represents a string that may come from an untrusted source, making its execution risky. It is passed as input to exec() function.

Example

untrusted_code = "import os; os.system('echo Malicious code executed!')"  # Example of potentially harmful code
try:
    exec(untrusted_code)
except Exception as e:
    print(f"An error occurred:{e}")

Explanation

  • untrusted_code = "import os; os.system('echo Malicious code executed!')": This simulates a potentially malicious code string that imports the os module and attempts to run a system command.
  • try:: This block attempts to execute the untrusted code.
  • exec(untrusted_code): This line executes the untrusted_code, which could be harmful.
  • except Exception as e:: This catches any exception that might occur.
  • print(f"An error occurred: {e}"): This prints an error message.

Output

Malicious code executed!


Python3

In Python 3, the Python exec() function remains a built-in function with the same core functionality as in earlier versions but with some improvements in terms of safety and flexibility. Notably, exec() in Python 3 is a function (in Python 2, it was a statement), which means you always use parentheses to call it. Python 3 lets you specify separate global and local namespaces more cleanly using the globals and locals parameters. No new features have been introduced for exec() in Python3.

Syntax

exec(code_string, globals_dict, locals_dict)

Explanation

  • exec(): Function executes the code in code_string within the given namespaces.
  • code_string: Python code to execute, as a string. It is passed as input to exec().
  • globals_dict: (Optional) Dictionary for the global namespace. It is passed as a parameter to exec().
  • locals_dict: (Optional) Dictionary for the local namespace. It is passed as a parameter to exec().

Example

code_string = "result = a + b"
globals_dict = {"a": 5}
locals_dict = {"b": 8}
exec(code_string, globals_dict, locals_dict)
print(locals_dict['result'])

Explanation

  • code_string = "result = a + b": Defines a code string that adds two variables and stores the sum in result.
  • globals_dict = {"a": 5}: Creates a globals dictionary with variable a.
  • locals_dict = {"b": 8}: Creates a locals dictionary with variable b.
  • exec(code_string, globals_dict, locals_dict): Executes code_string using globals_dict and locals_dict for global and local variables.
  • print(locals_dict['result']): Prints the value of result from the locals_dict.

Output

13


Global and Local Parameters

When using Python exec() in Python 3, you can specify global and local namespaces using dictionaries. The globals parameter defines the global variables and functions that the executed code can access, while the locals parameter defines the local namespace. If you omit locals, it defaults to the same as globals. By carefully controlling these dictionaries, you can limit the environment in which the dynamic code runs, improving security and preventing unintended side effects.

Syntax

exec(code_string, globals_dict, locals_dict)

Explanation

  • exec(): Function executes the code string code_string.
  • code_string: Python code to execute, as a string. It is passed as input to exec().
  • globals_dict: Dictionary representing the global namespace for the execution. It is passed as a parameter to exec().
  • locals_dict: Dictionary representing the local namespace for the execution. It is passed as a parameter to exec().

Example

global_x = 10
local_y = 5
exec("z = global_x + local_y", {"global_x": global_x}, {"local_y": local_y})
print(globals()['z'])

Explanation

  • global_x = 10: Defines a global variable global_x.
  • local_y = 5: Defines a local variable local_y.
  • exec("z = global_x + local_y", {"global_x": global_x}, {"local_y": local_y}): Executes the code string, using separate dictionaries for global and local variables. z will be available in global namespace.
  • print(globals()['z']): Prints the value of the global variable z, which was set by the exec() call.

Output

15


Conclusion

Python exec() is a powerful function for executing dynamically generated or loaded Python code represented as strings or code objects. It offers flexibility in running code whose content isn’t known until runtime. However, this power comes with significant security risks, especially when using exec() with untrusted input. It’s crucial to understand how to use globals and locals parameters to control the execution environment and limit potential vulnerabilities. While Python exec can be useful in specific cases, such as creating highly dynamic programs or implementing certain kinds of interpreters, it’s generally recommended to explore safer alternatives when possible and use exec() judiciously and carefully. Avoid using exec() if you are unsure about the input string.


Also Read

Python globals()

Python hasattr()


Python Reference

python exec()

Table of Contents