The Eval Function in Python: A Powerful but Dangerous Weapon

Release the superpower of Python as a dynamic language

Yang Zhou
Yang Zhou
May 16 · 5 min read

The eval function is a weapon to release the superpower of Python as a dynamic programming language.

Talk is cheap, let’s see it by a simple scenario:

On a normal working day, your boss came over to the software team and said,

“I need you guys to implement a function, which will receive two numbers a and b and a string op. The op, by the way, stands for an arithmetic operator, such as “+”, “-”, “*” and “/”. Your function needs to return the calculated result of a op b.”

Then he added another sentence,

“Don’t waste my time, I need you guys to implement it ASAP with elegant code.”

The C/C++ developer in your company thought about it a few minutes and wrote a long function including much switch-case code.

The function looked like the following:

The C/C++ programmer satisfied the needs within 10 minutes. Your boss would be happy enough if there were no Python developers in his company.

However, you, as a Python expert, finished this task within 10 seconds by one line of code:

def cal(a, b, op): return eval(f'{a} {op} {b}')

The rest, as they said, is history. Your boss was very happy and promoted you again. 🎉

Photo by Cytonn Photography on Unsplash

The above story, of course, is fictitious. Any resemblance to real persons, living or dead, is purely coincidental. But it does display how powerful the eval function is in Python. It gives us the ability to execute an expression dynamically.

For the above example, even if the input is a more complex string representing an arithmetic calculation, such as 2+3-4*7, we can still finish our task by one line of code:

def calculate(): return eval(input())

It’s elegant and powerful, isn’t it?

However, each coin has two sides, the eval() function may be dangerous if we cannot use it properly and carefully.

This article will introduce the uses and tricks of the eval function in Python from elementary to profound. After reading, handling this weapon will be a piece of cake for you. 🍰

Evaluate a Python Expression Dynamically

As its name implies, the eval() function is used to evaluate a Python expression. We just need to put an expression inside the function as a string, and it will execute the expression anytime we call it.

Under the hood, when the eval function works, it will do four steps:

  1. Parse the expression
  2. Compile the expression to bytecode
  3. Evaluate the bytecode
  4. Return the result

Generally speaking, all Python expressions are okay for the eval() function. Such as the follows:

>>> eval('2<9')
True

>>> eval('sum([1,2,3])')
6
>>> eval("print('Yang is handsome!')")
Yang is handsome!

However, statements and expressions are different things in Python. The eval() function cannot evaluate statements.

>>> eval("CyberPunk = 2077")Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<string>", line 1
CyberPunk = 2077
^
SyntaxError: invalid syntax

As the above example shows, if we put an assignment, which is a statement rather than an expression, inside the eval() function, an error will be raised.

Evaluate Pre-Compiled Expressions To Save Time

If we need to evaluate the same expression many times by the eval() function, using the built-in compile() function to compile it into bytecode in advance is a common trick to make our programs more efficient.

A simple example is as follows:

>>> code = compile("5+3-1", "<string>", "eval")
>>> eval(code)
7

Because the compile() function has compiled the code into bytecode already. There are only two steps the eval() function will do:

  1. Evaluate the compiled bytecode
  2. Return the result

Since two steps are faster than four steps, this is a good trick to speed up our code if we use the eval() function to run the same expression many times.

Customise Namespaces of the Eval Function

The eval() function has two more optional arguments, global and local. They are used to tell the eval() function which global or local namespace it should use respectively when evaluating the expression.

Let’s see how it works by an instance:

>>> x = 5
>>> eval("x+y")
Traceback (most recent call last):
...
NameError: name 'y' is not defined

As shown above, since the y variable isn’t in the global scope, the code will raise an error. We can fix this in the following way:

>>> x=5
>>> eval("x+y",{'x':x, 'y': 10})
15

This time, we add the y variable into the global scope by the second argument, and the function works fine now.

Therefore, as long as we are familiar with the rule of the variables’ scope in Python, the optional arguments are very helpful.

Be Careful of Untrusted Input

As mentioned, the eval() function is a powerful but dangerous weapon in Python. A dangerous weapon is not designed for newbies. Like only Bruce Lee can use a nunchaku perfectly, only senior Python developers can use the eval() function properly. This function could introduce huge security risks if we aren’t careful enough when writing it.

Let’s rethink one of the previous example code:

def calculate(): return eval(input())

To be honest, the above code is very dangerous in some scenarios.

For example, we put the above function into the programs of a web server to handle user input from a website. If the user happens to be a hacker, he may input the following string:

__import__('os').system('ls')

Since the eval() function will evaluate any Python expressions, the hacker can easily get a list of files and folders on the server.

This is not the worst case at all. If the hacker is evil enough and he inputs the following string:

__import__('os').system('rm -rf *')

To be honest, you probably will be fired if the above string is really evaluated by the eval() function.

Of course, there are many solutions to use the eval() function and avoid some invalid input at the same time, such as making some restrictions by the optional arguments. But we are not talking about the attacking and defending techniques in this article. (Python, by the way, is also a very popular language in the cyber security areas.)

As far as I am concerned, if you are not a high-level Python and cyber security expert, it is the best practice that never using the evel() function when the input sources are untrusted.

Conclusion

The eval() function in Python can evaluate expressions dynamically. It could be very powerful and elegant sometimes. However, a powerful weapon is not easy to master. There will be security risks if we use the eval() function inappropriately. Therefore, never using the eval() to evaluate untrusted input is a good idea.

Thanks for reading. If you like it, don’t forget to follow me to enjoy more great articles about programming and technologies!

Relative articles:

TechToFreedom

Dive into technology, investment and entrepreneurship.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store