Python exec() — A Hacker’s Guide to A Dangerous Function

Python’s exec() function executes the Python code you pass as a string or executable object argument. This is called dynamic execution because, in contrast to normal static Python code, you can generate code and execute it at runtime. This way, you can run programmatically-created Python code.

Have you ever wondered about the limits of a single line of Python code? Well, there are no limits to it—if you know this one powerful function. This tutorial shows you how to use Python’s built-in exec() function.

Python exec() Explained Illustrated

Usage Examples

Learn by example! Here are some examples of how to use the exec() built-in function:

>>> program = 'print("hello world")'
>>> exec(program)
hello world

First, you create a program which is only a string that contains Python code. Second, you run exec(program) to execute the program in Python.

>>> exec('x=2; y=4; print(x+y)')
6

The previous code snippet, you’ve seen how to run multiple “lines of code” in a single line of code. You create two variables x and y and print the sum of both. You compress all those lines into a single one by using the semicolon ;

Here’s how you can use the exec() statement within the exec() statement by giving the user the power to run some code in your environment. Be careful with that! This opens all kinds of security problems because any user can run virtually any program on your computer—a nightmare for security considerations!

>>> exec('x = input("Your code: "); exec(x)')
Your code: print('hi')
hi

So, how does the syntax formally look like?

Syntax Exec()

You can use the exec() method with three different argument lists.

Syntax: 
exec(object)
exec(object, globals)
exec(object, globals, locals) 
Argumentsobject A string or code object to be executed.
globalsOptional. A dictionary in which you can define variables that should be globally accessible by the executed object (local namespace).
localsOptional. A dictionary in which you can define variables that should be locally accessible by the executed object (global namespace).
Return ValueNoneReturns nothing but it may still have significant side effects!

Python exec() Return Value

The return value of exec() is None. However, it may have run all kinds of functions with all kinds of side effects such as changing the folder structure on your operating system, creating new files, deploying a Trojan horse, or hijacking your Bitcoins.


But before we move on, I’m excited to present you my new Python book Python One-Liners (Amazon Link).

If you like one-liners, you’ll LOVE the book. It’ll teach you everything there is to know about a single line of Python code. But it’s also an introduction to computer science, data science, machine learning, and algorithms. The universe in a single line of Python!

The book was released in 2020 with the world-class programming book publisher NoStarch Press (San Francisco).

Link: https://nostarch.com/pythononeliners

[Danger Zone] Python exec() User Input

You can use the exec() function to run code that is typed in dynamically by the user:

program = input('your code: ')
exec(program)

This is very dangerous because the user can actually run any code in your environment. If you run this on your server, the user may attempt to remove all files on your server! For example, the user may use the command os.system('rm -rf *') to remove all files and folders.

The execution of these two lines of code can be also graceful:

your code: print('hi')
hi

The user types in print('hi') as user input. This is taken as a string "print('hi')", packed into the program variable, passed into the exec(program) function, and executed.

Python exec() File

How to execute a file within a Python interpreter?

You can use the following powerful one-liner:

exec(open("filename.py").read())

The exec() function will run all the contents of the file filename.py on the computer on which it is executed.

Think of what you could do with this! Someone could deploy whole projects on another machine if they’ve gained access to the exec() function on a machine!

Python exec() Globals

Per default, Python passes all global names—the ones you can obtain with globals()—into the exec() function, so you can use variables you’ve defined outside the exec() function:

x = 'Alice'

program = '''
def f():
    print(x)

f()
'''

exec(program)
# 'Alice'

The result of this execution is the string 'Alice' on your shell. However, the variable x is defined outside of the program, so the exec() function has access to the whole program state.

If you don’t want to allow users of the exec() function to be able to access the whole program state, you can overwrite the global names by providing your custom dictionary of names and their values.

Here’s how you create a clean slate for your exec() program execution:

x = 'Alice'

program = '''
def f():
    print(x)

f()
'''

exec(program, dict())

The output is now:

Traceback (most recent call last):
  File "C:\Users\xcent\Desktop\Finxter\Blog\HowToConvertBooleanToStringPython\code.py", line 14, in <module>
    exec(program, dict())
  File "<string>", line 6, in <module>
  File "<string>", line 3, in f
NameError: name 'x' is not defined

The reason for this NameError is that the global variable x is not part of the new global namespace because you passed the empty dictionary as a globals argument into the exec() function.

Python exec() Locals

In a similar manner, you can pass a dictionary as a second argument to the exec() function to customize the use of your local namespace. Otherwise, Python will just use the global default namespace of your program as a local namespace.

This throws a NameError because variable x does not exist in the global namespace—and therefore it’s not visible within the function definition:

x = 'Alice'

program = '''
def f():
    print(x)


f()
'''


exec(program, dict(), {'x':42})

However, if you use the variable x in a local context within your program string, it works!

x = 'Alice'
program = 'print(x)'
exec(program, dict(), {'x':42})
# OUTPUT: 42

The same selection of the empty globals dictionary (first argument) and the locals dictionary (second argument) with the definition of the variable x leads to a drastically different result when accessing x within different namespaces.

Python exec() vs eval()

Python’s exec() function takes a Python program, as a string or executable object, and runs it. The eval() function evaluates an expression and returns the result of this expression. There are two main differences:

  • exec() can execute all Python source code, whereas eval() can only evaluate expressions.
  • exec() always returns None, whereas eval() returns the result of the evaluated expression.
exec('x=2;y=2;z=x*y;print(z)')
# 4

print(eval('2*2'))
# 4

Python exec() Import

Can you import other libraries or modules within an exec() execution? The answer is yes! Just call exec('import xxx; ...') to import library xxx into the local namespace of the exec computation.

program = '''
import random
print(random.randint(0,9))
'''

exec(program)
# Example Output: 2

In my execution, the output was 2 but it’ll be different in your case due to the nature of the random function. The point is that you can import all standard Python libraries within an exec() function by using the standard import xxx pattern.

This also works if you use the random module in another scope (such as within a function):

program = '''
import random
def f():
    print(random.randint(0,9))
f()
'''

exec(program)
'''
4
'''

Python exec() Multiple Lines

You can simply run the exec() function on multiple lines of Python code by using the semicolon operator to separate the statements:

# Instead of ...
a = 2
b = 4
c = b/a
print(c)

# Write ...
exec('a=2;b=4;c=b/a;print(c)')

This only works if there are no indented code blocks such as function definitions or if statements. If there are, just use a multiline string:

program = '''
a = 2
b = int(input('your number: '))
if b>a:
    print('Yes!')
'''

exec(program)

A less Pythonic way is to use the '\n' character instead of the newlines to save some space.

program = "a = 2\nb = int(input('your number: '))\nif b>a:\n    print('Yes!')"
exec(program)

Summary

Python’s exec() method executes the Python code you pass as a string or executable object argument.

>>> exec('x=2; y=4; print(x+y)')
6

This is called dynamic execution because, in contrast to normal static Python code, you can generate code and execute it at runtime. This way, you can run programmatically-created Python code.

Be careful not to allow unauthorized people to run Python’s exec() on a Python shell on your computer or server because it opens up all kinds of security vulnerabilities.

I hope you enjoyed the article! To improve your Python education, you may want to join the popular free Finxter Email Academy:


Do you want to boost your Python skills in a fun and easy-to-consume way? Consider the following resources and become a master coder!

Where to Go From Here?

Enough theory, let’s get some practice!

To become successful in coding, you need to get out there and solve real problems for real people. That’s how you can become a six-figure earner easily. And that’s how you polish the skills you really need in practice. After all, what’s the use of learning theory that nobody ever needs?

Practice projects is how you sharpen your saw in coding!

Do you want to become a code master by focusing on practical code projects that actually earn you money and solve problems for people?

Then become a Python freelance developer! It’s the best way of approaching the task of improving your Python skills—even if you are a complete beginner.

Join my free webinar “How to Build Your High-Income Skill Python” and watch how I grew my coding business online and how you can, too—from the comfort of your own home.

Join the free webinar now!