0

I am trying to use EVAL() to evaluate two statements at the same time but I am having some issues:

metrics_dict = {}

def testA(n):
    print ("testA done")
    global metrics_dict
    result = n**n
    metrics_dict["metricA"] = result
    return result

def testB(n):
    print ("testB done")
    global metrics_dict
    result = n**n
    metrics_dict["metricB"] = result
    return result

def testC(n):
    print ("testC done")
    global metrics_dict
    result = n**n
    metrics_dict["metricC"] = result
    return result

logic = "testA(2) > 10 and testB(3) > 0"

if I run the eval on "logic", like this:

x = eval(logic)

I get "testA done" and FALSE, and I believe this happens because since testA is FALSE, the EVAL() does not proceed with the second check for testB, in addition to that my metrics_dict only has metricA in it, so my question is, is there a way to force the eval to go over all the checks within my logic statement, I need to be able to check and record both tests all the the time, it does not matter if it is a FALSE, FALSE or FALSE, TRUE or TRUE, FALSE or TRUE, TRUE.

thaks all

  • I think eval() will evaluate your expression as a whole. In other words if your first case is False then the whole expression will be False no matter the result of TestB(3) > 0. Can you try with first expression evaluating to True? – El Pandario May 09 '22 at 09:37
  • 1
    This really has nothing to do with `eval`, and simply all to do with how `and` works. – deceze May 09 '22 at 09:42
  • Do you know that [Evil really is dangerous](https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html)? – Matthias May 09 '22 at 09:43

1 Answers1

3

Rather than messing with eval, where you're not going to be able to sidestep how AND works logically, you should consider encoding your check logic as a collection of independent statements:

>>> logic = [testA(2) > 10, testB(3) > 0]
testA done
testB done
>>> logic
[False, True]

And then you can still get your end result via all(logic) or some other such reduction.

Dominik Stańczak
  • 2,046
  • 15
  • 27
  • thanks for the answer. in this case I am reading the logic from an external file, basically the user creates a yaml file where she/he writes the condition and my code has to read the condition and do the evaluation, that is why I need to use eval – Ricardo de Castro May 09 '22 at 09:48
  • @Ricardo If you want your user to write `and` but have it not behave like a short-circuiting `and`, you're getting into territory of having to manually parse the code and evaluate it according to your own rules, which seems… problematic. In this particular case you can maybe just split the string by `'and'` and `eval` the individual parts, but if you want to support more complex logic that'll become difficult. Also, short-circuiting behaviour with boolean operators is pretty universal, so changing that may undermine the user's expectations. – deceze May 09 '22 at 09:53
  • 1
    thanks all, @Dominik answer kind of gave me an idea, instead of using AND, i might ask the user to write the logic as: logic = "testA(2) > 10, testB(3) > 0" and i get a tuple back, with this (FALSE, TRUE) tuple for example I can advance with my code. – Ricardo de Castro May 09 '22 at 09:58
  • Yup, that sounds like it would work! – Dominik Stańczak May 09 '22 at 10:15