Use of Eval in Python

What does Python's eval() do?

The eval function lets a Python program run Python code within itself.

eval example (interactive shell):

>>> x = 1
>>> eval('x + 1')
2
>>> eval('x')
1

Use of eval in Python?

eval and exec are handy quick-and-dirty way to get some source code dynamically, maybe munge it a bit, and then execute it -- but they're hardly ever the best way, especially in production code as opposed to "quick-and-dirty" prototypes &c.

For example, if I had to deal with such dynamic Python sources, I'd reach for the ast module -- ast.literal_eval is MUCH safer than eval (you can call it directly on a string form of the expression, if it's a one-off and relies on simple constants only, or do node = ast.parse(source) first, then keep the node around, perhaps munge it with suitable visitors e.g. for variable lookup, then literal_eval the node) -- or, once having put the node in proper shape and vetted it for security issues, I could compile it (yielding a code object) and build a new function object out of that. Far less simple (except that ast.literal_eval is just as simple as eval for the simplest cases!) but safer and preferable in production-quality code.

For many tasks I've seen people (ab-)use exec and eval for, Python's powerful built-ins, such as getattr and setattr, indexing into globals(), &c, provide preferable and in fact often simpler solutions. For specific uses such as parsing JSON, library modules such as json are better (e.g. see SilentGhost's comment on tinnitus' answer to this very question). Etc, etc...

How to use eval() function on string of ints?

If You want to get the average of those integers in that string this is one way:

myStr = '3848202160702781329 2256714569201620911 1074847147244043342'
print(sum(lst := [int(x) for x in myStr.split()]) / len(lst))

basically You get the sum of a list of those integers that are in that string and also use that operator (forgot the name) to assign that list to a variable while simultaneously return that value, then just divide the sum by the length of that list

EDIT1, 2, 3: just remembered, it is called walrus operator, some info can be found here (video by Lex Fridman) and here, as well as other places, also it requires Python version of 3.8 or higher

EDITn: the reason behind the use of the walrus operator is that it allowed to not repeat code in this one-liner, otherwise the list comprehension would have been used twice (in sum and in len) which could affect performance for very large lists (and I wanted it to be a one-liner)

Why is using 'eval' a bad practice?

Yes, using eval is a bad practice. Just to name a few reasons:

  1. There is almost always a better way to do it
  2. Very dangerous and insecure
  3. Makes debugging difficult
  4. Slow

In your case you can use setattr instead:

class Song:
"""The class to store the details of each song"""
attsToStore=('Name', 'Artist', 'Album', 'Genre', 'Location')
def __init__(self):
for att in self.attsToStore:
setattr(self, att.lower(), None)
def setDetail(self, key, val):
if key in self.attsToStore:
setattr(self, key.lower(), val)

There are some cases where you have to use eval or exec. But they are rare. Using eval in your case is a bad practice for sure. I'm emphasizing on bad practice because eval and exec are frequently used in the wrong place.

Replying to the comments:

It looks like some disagree that eval is 'very dangerous and insecure' in the OP case. That might be true for this specific case but not in general. The question was general and the reasons I listed are true for the general case as well.

what is the difference between eval and int

eval evaluates the python expression. In python 3, numbers starting by 0 aren't allowed (except for 0000, see Why does 000 evaluate to 0 in Python 3?). In python 2, those are interpreted as octal (base 8) numbers. Not better... (python 3 base 8 now uses exclusively Oo prefix)

int performs a string to integer conversion, so it cannot evaluate a complex expression (that you don't need), but isn't subjected to this leading zero syntax.

Another nice feature is that you can check if the entered expression is an integer by using a simple and qualified try/except block:

while True:
try:
age = int(input("enter age"))
break
except ValueError:
print("Retry!")

(with eval you would have to protect against all exceptions)

Advice: use int, because it's safer, doesn't have security issues (eval can evaluate any expression, including system calls and file deletion), and suits your purpose perfectly.

Note: the above code is still unsafe with python 2: input acts like eval. You could protect your code against this with the simple code at the start of your module:

try:
input = raw_input
except NameError:
pass

so python 2 input is not unreachable anymore and calls raw_input instead. Python 3 ignores that code.

How to use eval() function with a list of variables?

eval takes local variables as third argument(reference),
so you can do this:

from sympy import Symbol
zs = [Symbol('x'), Symbol('y')]
eval('x+y', None, dict([z.name, z] for z in zs))

However, maybe you should use parse_expr which is part of SymPy.

from sympy import Symbol
from sympy.parsing.sympy_parser import parse_expr
zs = [Symbol('x'), Symbol('y')]
parse_expr('x+y', local_dict=dict([z.name, z] for z in zs))

Safely using eval to calculate using the math module in python

Regarding "safely", it depends on what you mean. You can provide access to your global environment easily enough, giving the expression access to whatever you've imported. But there is nothing to stop a user from entering an expression that can do unintended things, so if the expression is coming from an untrusted user, then you should avoid the use of eval.

That having been said, you can make your example work as follows:

>>> from math import *
>>> eval("sin(30)", globals())
-0.9880316240928618
>>>

Note that in this example, 30 is being interpreted as radians rather than degrees.

Using python's eval() vs. ast.literal_eval()

datamap = eval(input('Provide some data here: ')) means that you actually evaluate the code before you deem it to be unsafe or not. It evaluates the code as soon as the function is called. See also the dangers of eval.

ast.literal_eval raises an exception if the input isn't a valid Python datatype, so the code won't be executed if it's not.

Use ast.literal_eval whenever you need eval. You shouldn't usually evaluate literal Python statements.



Related Topics



Leave a reply



Submit