1

I am wondering if there is a simple way to avoid using eval for the following code:

eval('6001 >= 6005') 

I have been searching for a couple hours trying to find a simple alternative after learning eval is not good practice, especially when you don't know who is going to be using the program.

The background to my use of this is something like this:

each of the two comparison variables will be a value from a pandas dataframe column, so it could also look like this:

eval('"my_city_name" == "your_city_name"') 

Any help is greatly appreciated! Thanks

6
  • pandas' eval is different from the eval function. It's not dangerous. However, you have many alternatives like query and boolean indexing. You need to show a sample input-output though. Commented Jul 17, 2017 at 19:13
  • is pandas' eval safe? I tried a hack that I saw somewhere like so: 'pandas.eval(input())' and it didn't break like it should have. Although there was no output, it just froze the program so I wasn't sure. Commented Jul 17, 2017 at 19:55
  • Well it only supports arithmetic operations so I don't know how it would be dangerous. What was your input? Commented Jul 17, 2017 at 19:59
  • 3
    just tried this: pd.eval("os.remove('text.txt')") with an error of WindowsError: [Error 2] The system cannot find the file specified: 'text.txt', so I'm not sure how safe it is Commented Jul 17, 2017 at 20:05
  • Yes it seems not safe at all. Apologies. Commented Jul 17, 2017 at 20:07

2 Answers 2

5

You could avoid the eval() by implementing the comparisons you want to allow:

STRINGS = ['6001 >= 6005', '"my_city_name" == "your_city_name"', '13 != 14', '1 < 4'] COMPARISONS = { '==': lambda a, b: a == b, '!=': lambda a, b: a != b, '>=': lambda a, b: a >= b, } for string in STRINGS: operand1, comparison, operand2 = string.split() if comparison in COMPARISONS: print(string, (COMPARISONS[comparison])(operand1, operand2)) else: print(string, "Unknown comparison") 

This is just an example, in reality you'd need to do some type checking, number conversion and so forth but the key is to decide which comparisons matter to you.

Sign up to request clarification or add additional context in comments.

2 Comments

I was also thinking of this, but for my application it would be easier if the string was not split in case one of the operands had more than one word. I supposed I could have logic to deal with that case, but I just wanted to check here first to see if anyone had any quick and clever ways around this. Thanks for the advice!
ended up doing a spinoff of this that was catered to my application, after doing some more research on alternatives to eval(), seems there aren't any! Thanks for the input!
0

Here is what i ended up with:

def transform(self, attribute): try: attribute = float(attribute) if math.isnan(attribute): attribute = "NULL" print type(attribute) return attribute except ValueError: attribute = str(attribute) print type(attribute) return attribute def equals(self, attribute, value): return self.transform(attribute) == self.transform(value) def not_equals(self, attribute, value): return self.transform(attribute) != self.transform(value) def greater_than(self, attribute, value): return self.transform(attribute) > self.transform(value) def greater_than_equal(self, attribute, value): return self.transform(attribute) >= self.transform(value) def less_than(self, attribute, value): return self.transform(attribute) < self.transform(value) def less_than_equal(self, attribute, value): return self.transform(attribute) <= self.transform(value) 

Since I only needed a select few of the operators, this was the best solution that I could come up with. transform() is just to take care of some comparison issues I ran into with my particular dataset. Hopefully this can help someone in the future! If anyone has comments or suggestions please let me know.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.