Explain Codes LogoExplain Codes Logo

How do I execute a string containing Python code in Python?

python
exec-function
security-implications
higher-order-functions
Alex KataevbyAlex Kataev·Feb 12, 2025
TLDR

To perform execution of Python code within a string, use the exec() function:

exec('print("Hello SO users!")') # Put on your wizard's hat, we're executing magic strings!

This will produce an output: Hello SO users! Remember, wield this power responsibly. It can open up a pandora's box of security issues with naive or untrusted input.

Weighing the pros and cons: to exec or not to exec

Invoking exec() is not a decision to be made lightly. Its power to execute dynamic Python code is alluring, but masked behind this allure are security implications and potential performance slowdowns. Instead of making a beeline for exec, evaluate if using higher-order functions, classes, or modules, these alternatives can often encapsulate the desired dynamic behavior without the associated risks.

However, should exec be your method of choice, remember to prioritize performed security checks on untrusted inputs to fend off any potential code injection attacks. Validate and sanitize the strings before passing them into the jaws of exec. Here's how you can handle variables and output within exec:

from io import StringIO import sys code = 'print("Hello again SO-ers!")' old_stdout = sys.stdout new_stdout = StringIO() sys.stdout = new_stdout try: exec(code) # Try not to summon Cthulhu finally: sys.stdout = old_stdout output = new_stdout.getvalue() new_stdout.close() print(f'Exec function output: {output}')

Building a safe house: confining the execution environment

Just as you'd house train a pet, it's best to house-train your exec calls. In other words, limit the namespace it has access to. This reduces the risk of the user accidentally (or intentionally) messing up the global namespace:

namespace = {} # Constraining exec to its own sandbox, because who knows what it might do otherwise. exec('foo = "This is foo"', namespace) print(namespace['foo']) # Outputs: This is foo

Looking for safer harbors: alternatives to exec

If you can avoid using exec, even better. Opting for higher-order functions can often substitute for using exec. In-built Python functions like map(), filter(), and reduce() can flexibly manipulate data, posing considerably lesser security risk.

Also, consider class-based and factory patterns, they can tailor dynamic behavior using inheritance and method overrides, thereby entirely eliminating the need for exec.

Drawing the battle lines: setting restrictions for exec

In unavoidable scenarios where exec is the only option, utilise safe_dict to restrict exec within its execution box:

safe_dict = {'__builtins__': None} exec('print("Safe and sound with safe_dict!")', safe_dict) # My exec is in its secure playpen

Beware of false senses of security such as the removal of globals and builtins, which are defective in terms of blocking code injection. Whitelisting is often a safer practice realised, but as always, tread with caution.