[Tutor] Is there a way to store and later use comparison operators (<, <=, =, >=, >) ?

Peter Otten __peter__ at web.de
Thu Apr 30 00:49:12 CEST 2015


boB Stepp wrote:

> On Wed, Apr 29, 2015 at 3:46 PM, Marc Tompkins <marc.tompkins at gmail.com>
> wrote:
>> On Wed, Apr 29, 2015 at 1:10 PM, boB Stepp <robertvstepp at gmail.com>
>> wrote:
>>>
>>> Python 2.4.4, Solaris 10.
>>>
>>> I have some functions that I believe I could collapse into a single
>>> function if I only knew how:
>>>
>>> def choose_compare(operator, value0, value1, pass_color, fail_color):
>>>     """
>>>     Perform the comparison indicated by operator. Return pass_color if
>>> true, fail_color if false.
>>>     """
>>>     if operator == '<':
>>>             return less_than(value0, value1, pass_color, fail_color)
>>>     elif operator == '<=':
>>>         return less_than_or_equal(value0, value1, pass_color,
>>>         fail_color)
>>>     elif operator == '=':
>>>         return equal(value0, value1, pass_color, fail_color)
>>>     elif operator == '>':
>>>         return greater_than(value0, value1, pass_color, fail_color)
>>>     elif operator == '>=':
>>>         return greater_than_or_equal(value0, value1, pass_color,
>>> fail_color)
>>>     else:
>>>         print 'WarningMessage = "Invalid comparison operator in
>>> function, choose_compare(). at Please contact script administrator for
>>> assistance.";'
>>>
>>> def less_than(value0, value1, pass_color, fail_color):
>>>     """
>>>     See if value0 is less than value1. If true, return pass_color. If
>>> false, return fail_color.
>>>     """
>>>     if value0 < value1:
>>>         return pass_color, True
>>>     else:
>>>         return fail_color, False
>>>
>>> def less_than_or_equal(value0, value1, pass_color, fail_color):
>>>     """
>>>     See if value0 is less than or equal to value1. If true, return
>>> pass_color. If false, return fail_color.
>>>     """
>>>     if value0 <= value1:
>>>         return pass_color, True
>>>     else:
>>>         return fail_color, False
>>>
>>> ... 3 more functions ...
>>>
>>> I won't give the remaining functions for the other comparison
>>> operators. The string variable, operator, is originally populated from
>>> a data file, which tells what type of comparison needs to be made. The
>>> last two functions I gave (and the ones I omitted giving) all follow
>>> the same exact pattern. I know there has to be some way to replace
>>> these 5 functions with 1, but what experimentation I have done to date
>>> has not worked.
>>>
>>> Also, what about the first function above? I could use 2 dictionaries,
>>> 1 for calling the 5 functions and one to pass the arguments, but is it
>>> worth doing this? Or, I would not be surprised if there is a much
>>> better way! ~(:>))
>>>
>>> Thanks!
>>
>>
>> Here's what I came up with:
>>
>> def choose_compare(operator, value0, value1, pass_color, fail_color):
>>     comps = {"=":"==", "<":"<", ">":">", "<=":"<=", ">=":">="}
>>     if operator in comps.keys():
>>         operator = comps[operator]
>>         if eval("{} {} {}".format(value0, operator, value1)):
>>             return pass_color, True
>>         else:
>>             return fail_color, False
>>     else:
>>         print('WarningMessage')
>>
>> I would ordinarily avoid eval() like the plague, but I think that this
>> sanitizes the input pretty effectively.  I had to make comps a dict
>> instead of a list because (in your example, anyway) you're using a single
>> equals
>> sign to check for equality, which throws a Syntax Error (e.g.  "if 1 = 2"
>> instead of "if 1 == 2").
> 
> I could deal with the "=" issue by either reformatting my data file to
> use "==" in place of "=", or when I parse the data file, do the
> replacement there. A list instead of the dictionary looks a little
> easier on my eyes.
> 
> The list has me so leery of eval and exec that I totally forgot about
> this possibility! There are only two places in my program where I read
> information directly into my program: 1) The data file, or 2) how the
> user of the planning software names his regions of interest (ROI) in
> the planning system software. I will reexamine my checks of (1). For
> (2) the planning software already has its own checks, which would
> filter out a lot. And I am checking the ROIs to see if they are
> present in the data file *exactly* as given in the data file;
> otherwise, I reject them.
> 
> So I have stumbled (With your gracious help!) into a legitimate use of
> eval()?

No. To expand on Marks hint here's how to do it without evil eval().

import operator

comps = {
    "=": operator.eq,
    "<": operator.lt,
    ">": operator.gt,
    # ...
}

def choose_compare(operator, value0, value1, pass_color, fail_color):
    op = comps[operator]
    if op(value0, value1):
        return pass_color, True
    else:
        return fail_color, False

print(choose_compare("=", 1, 1, "red", "blue"))
print(choose_compare("<", 1, 2, "red", "blue"))
print(choose_compare("<", 2, 1, "red", "blue"))

Rule of thumb: when you think you need eval() you're wrong.



More information about the Tutor mailing list