Dynamic expression in Python [closed]
I will get condition from json file where the condition is '<=' and need to compare two columns containing dates.
So I tried as below:
left = y['predicate']['left']
right = y['predicate']['right']
grp1 = y['groupby']['groupByFields']
grp2 = y['groupby']['aggregateField']
ope = y['groupby']['aggregateOperation']
res = y['groupby']['result']
logic = y['predicate']['logic']
result[left] = pd.to_datetime(result[left])
result[right] = pd.to_datetime(result[right])
res = result.loc[result[left] + eval(logic) + result[right]]
By using the following code it is working perfectly
res = result.loc[result[left] <= result[right]]
and i tried these also
res = result.loc[eval(str(result[left]) +" " + logic +" " + str(result[right]))]
I am getting error.
Solution 1:
Please do not use eval
. It is very dangerous - almost always more dangerous than you expect - and there is rarely a good reason to use it. The current problem is definitely not a good reason.
Instead, simply use the logic
string to look up a function which can do the comparison. The standard library module operator
provides such functions:
import operator
ops = {
'==': operator.eq, '!=': operator.ne,
'<=': operator.le, '>=': operator.ge,
'<': operator.lt, '>': operator.gt
}
# later:
res = result.loc[ops[logic](result[left], result[right])]
# Error handling is left as an exercise.
You can also create such named functions yourself:
def eq(x, y):
return x == y
Or use lambda
: ops = {'eq': (lambda x, y: x == y), ...
In all cases, the lookup should contain the functions themselves, not the result of a call.
Solution 2:
This is because str(result[left])
and str(result[right])
cause these dataframe columns to be printed, while you want them to become result[left] {logic} result[right]
.
logic = ">=" # For example
res = result.loc[eval(f"result[left] {logic} result[right]")]
using f-string formatting (Python 3.6+)
Note: Use eval
are your own risk. I would advise using other methods. There's other comments that outline some.