boB Stepp wrote: > On Wed, Apr 29, 2015 at 3:46 PM, Marc Tompkins <marc.tompk...@gmail.com> > wrote: >> On Wed, Apr 29, 2015 at 1:10 PM, boB Stepp <robertvst...@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().@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. _______________________________________________ Tutor maillist - Tutor@python.org To unsubscribe or change subscription options: https://mail.python.org/mailman/listinfo/tutor