jGraves
jGraves

Reputation: 83

Alternative to eval() for evaluating string expressions

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

Upvotes: 1

Views: 3994

Answers (2)

jGraves
jGraves

Reputation: 83

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.

Upvotes: 0

cdlane
cdlane

Reputation: 41925

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.

Upvotes: 5

Related Questions