Whilst optimising a program I wrote about a year ago, I came across the eval function. My approach using eval for code optimisation is discussed later in this article.
What is the eval function?
In summary, eval() will interpret any string argument parsed into it and execute it as Python code. A simple example is adding two numbers as shown below, The string ‘number + 2’ passed through eval gets executed and returns the value 3.
>> number = 1
>> eval('number + 2')
Additionally, eval only works with an expression. Trying to pass a statement will cause a syntax error as shown in example below.
>> eval('number = 1 + 2')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
num = 1 + 2
SyntaxError: invalid syntax
Wrong way to use eval():
Due to the way eval runs you really want to avoid passing untrusted sources into the function. It could potentially be used in a harmful way. Check out the code below:
>>> user_input = input('Enter command:')
eval(user_input)Result: /Users/<local directory>
Imagine replacing the ‘pwd’ with ‘rm -rf *’ this could cause significant chaos on a server.
How I used eval the right way?
I read a book which talked about the advantages of using data structures to reduce the number of lines of code.
I had five functions with different parameters making external calls to the same library. I wanted to reduce these to a single function by using data structures.
To solve this I stored all the function names as a string in a dictionary. Then using the format function which is excellent for string formatting and substitution, I created the exact function call as a string, including its parameters.
Finally, the resulting string was parsed into eval to be execute as a function call. I created a prototype of how I achieved this in the github repository below. The prototype demonstrates the idea in a way that is simple to understand.
The code is available on my GitHub page: https://github.com/solomonakinyemi/using_eval_python
The Prototype for demonstration
I created a simple program that makes function calls to the Chuck Norris Jokes APIs.
Program is mainly broken into three main sections:
- The call function
- The main function
- The shared library
The call function:
The call_function is the main focus of this program. What we do here is parse in the shared library object called “module”, a “function_selector” string which holds the key used to select a specific function from the dictionary of function names and the “param” dictionary which holds all the parameters required for the function selected.
We can see in the code snippet on line 3 the functions that are available, they are: get_chuck_joke_category, get_chuck_joke_id and get_url_content
The function string is created in the ‘function_string’ variable which also includes the parameters for that function. A good example is on line 10 where we create the function string for get chuck category. We create a category parameter as part of the “get_chuck_joke_category” function string.
The function string is executed using eval on line 17, with the results being returned to the response variable on line 17.
The main function:
The main function is used to run the program. We have a list called function_to_call which holds a list of the function call keys used to select a function.
Furthermore, we have a list named “category_” which shows the different categories available to the “get_chuck_joke_category” function. There are three Chuck Norris Jokes categories available in this program — movie, sport and music. An instance of the shared library object is created which we talk about in the next section.
Moreover, we have a simple for loop used to iterate through the function_to_call list on line 3 which holds the keys to access specific functions. Finally we make a call to “call_function” which we talked about above and the result is stored in a dictionary.
The class library:
The class library represents a shared library which basically makes https GET request to the Chuck Norris Jokes APIs. It holds the functions we are trying to access from our script.
In summary, I can understand why eval is a function that shouldn’t be used lightly. Furthermore, I think there is a place for eval in programs as it must have been created for a reason.
Things to be mindful of when using eval:
- Restricting the scope of the function/string passed into it
- Limiting the exposure to known sources only
- Understanding the impact it can have on your program
I would love to hear your opinion. Finally, does anyone out there use the eval?