'Is there a way to use eval() and a dictionary if input could be None?
I have some code with a lot of stacked if statements that I'm trying to make more pythonic. One of the segments of code boils down to three separate "values".
0.9 if 10<x>=20
0.75 if x>20
1 if x<10 or x is None
I tried sticking this in a dictionary to run through a function I made for a less complex (integers only) dictionary but am not sure how to handle None inputs.
def wallrat(val, table):
try:
# Create true/false list based on input value
chks = [eval(v.replace('x',str(val))) for v in table.values()]
# Find which value is true and verify that there's only one true value
if True in chks and chks.count(True) == 1:
# find the key that's true
v = chks.index(True)
table_list = list(table)
# Loop through keys and values in dictionary
return table_list[v]
age_dict = {0.9: '10< x >=20', 0.75: 'x > 20', 1:'x<10 or x is None'}
The above code obviously errors since if x == None, it can't do the other evaluations of 10< None >=20. I'm not sure how to pythonically handle this situation. Is it even possible to have a dictionary that tests both None and ints/floats? Or am I stuck having to use only x < 10 and use a separate segment of code to output the value of 1 if the input is None?
EDIT: I don't want to delete the question, but ended up just utilizing an If ... is not 'None' and an else statement to capture the 'None' = 1 assignment.
Comments and answers may provide helpful reconsideration to others utilizing eval(). In my specific use-case, there is no way for the input to contain malicious strings due to what the input data is (GIS feature class tables with integer fields or a coded int variable based on input date fields). Regardless though, I wasn't aware of the concerns about using eval() and the comments provide good information IMO.
Solution 1:[1]
You can use a list of lambdas that contain the logic you need instead of eval as it is a potential security risk and almost always not needed.
checks = [lambda x: .75 if x > 20 else ..., lambda x: 1 if x is None or x < 10 else ...]
Solution 2:[2]
If you want to achieve this if/else test in a single line, then using the python ternary syntax is probably the most readable option, and much safer & faster than eval with a dictionary of tests:
1 if x is None or x < 10 else 0.9 if 10 <= x <= 20 else 0.75
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | mwo |
| Solution 2 | match |
