5

I know that I can try-except with the eval itself, but I want to use it in list_comprehensions or map:

[eval(x) if isevaluable(x) else x for x in some_list]

My driving to do so: I get argument from sys.argv - which can be int\float\built-in-constants (especially True, False, None). I want to casting them all in a simple & clean way.

[Note: safe-eval isn't the issue here (even it's indeed recommended)]

alikyos
  • 86
  • 1
  • 7
  • why not wrapping the eval() with your own function that try-catch it? eg "[my_safe_eval(x) for x in some_list]"? – Ronen Ness Jul 15 '15 at 07:28
  • @Ness I thought of that, but he might not want the code to actually execute :) Say it's removing a file, and he wants the result in the list. then the list objects will be faulty because the `try / except` will remove the file in that eval instance. – Torxed Jul 15 '15 at 07:29
  • @Ness, it's a good idea - but I wonder if there is built-in\exist method (or other trick) for that. – alikyos Jul 15 '15 at 07:34
  • @Torxed I guess we need to ask OP why he wants to filter evaluable elements of a list. It looks like XY-problem to me – Konstantin Jul 15 '15 at 07:34
  • 1
    What are you *actually* trying to achieve? The likelihood that `eval` is the correct way to do it is pretty small. – jonrsharpe Jul 15 '15 at 07:34
  • 1
    `ast.literal_eval(string_value)` – Łukasz Rogalski Jul 15 '15 at 07:45
  • possible duplicate of [Python: make eval safe](http://stackoverflow.com/questions/3513292/python-make-eval-safe) – Łukasz Rogalski Jul 15 '15 at 07:46

2 Answers2

1

An obvious solution that may or may not work for your particular eval string.

def isevaluable(s):
    try:
        compile(s, "bogusfile.py", "exec")
        return True
    except:
        return False

This compiles the code, checking for syntax errors etc. Will not catch all your logical issues but it will check programmatical issues before shooting it into eval which could cause all kinds of troubles.

I thought of doing:

def isevaluable(s):
    try:
        eval(s)
        return True
    except:
        return False

But remember that then you'll execute your string which might obscure your result putting it into your list.
For instance if your string is rm /tmp/cache.txt which will give a positive result in your isevaluable and a negative result in your [eval(x) ...] because it got removed in the try statement.

In this case, compile() is a better alternative. It probably is in any example.

Torxed
  • 22,866
  • 14
  • 82
  • 131
1

First of all, if your x only contains a literal of type - strings, numbers, tuples, lists, dicts, booleans, and None - you can use ast.literal_eval , which is much more safer than eval() function.

ast.literal_eval(node_or_string)

Safely evaluate an expression node or a Unicode or Latin-1 encoded string containing a Python literal or container display. The string or node provided may only consist of the following Python literal structures: strings, numbers, tuples, lists, dicts, booleans, and None.

Also, you will most probably have to define the function isevaluatable() yourself , example -

def isevaluatable(s):
    import ast
    try:
        ast.literal_eval(s)
        return True
    except ValueError:
        return False

Then you can do

import ast [ast.literal_eval(x) if isevaluatable(x) else x for x in some_list]

An easier way to do this would be to make the function return the required value itself

def myeval(s):
    import ast
    try:
        return ast.literal_eval(s)
    except ValueError:
        return s

And then do -

[myeval(x) for x in some_list]
Community
  • 1
  • 1
Anand S Kumar
  • 88,551
  • 18
  • 188
  • 176
  • isn't `ast.literal_eval` equivalent to `eval(x, {}, {})` (empty dicts for `globals` & `locals`)? – alikyos Jul 15 '15 at 12:43
  • ok - is see the link to this [Eval really is dangerous](http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html) – alikyos Jul 15 '15 at 12:59
  • I do not think so , even without globals and locals you would still be able to run Python statements right? That would not be possible with ast.literal_eval() . – Anand S Kumar Jul 15 '15 at 12:59
  • I doesn't detailed my propose, I meant "equivalent" from the safe-eval side-of-view – alikyos Jul 15 '15 at 13:51