简体   繁体   中英

Less than Or Greater Than Comparison as a Variable in Python

I have a block of code in a function that does some comparisons, namely:

if customer_info['total_dls'] < min_training_actions \
or customer_info['percentage'] > train_perc_cutoff:
    continue
elif customer_id not in test_set \
or test_set[customer_id]['total_dls'] < min_testing_actions:
    num_uncertain +=1
    continue
elif test_set[customer_id]['percentage'] <= test_perc_cutoff:
    num_correct +=1
else:
    num_incorrect +=1

Now sometimes I need to do those comparisons to be greater than, and sometimes I need them to be less than. All of the rest of the code is exactly the same. Now, I could just make two functions that reuse basically the same code, but before I do, is there some clean way to variabalize the comparison operator, so I could just use the same block of code and pass in the comparison as a variable? Something like: compare(var1, var2, polarity) . I know I can make this myself, but I'm wondering what the standard is in cases like this. Is there some pretty pythonic way of doing this I'm unaware of?

[Edit] Adding emphasis to the most important part of the question [/Edit]

You can use the operator module ; it has functions that act as the comparison operators:

import operator

if foobar:
    comp = operator.lt
else:
    comp = operator.gt

if comp(spam, eggs):

This'll use either test if spam is less then, or greater then eggs , depending on the truth of foobar .

This fits your comparison as a variable requirement exactly.

This is certainly what I'd use to avoid repeating myself; if you have two pieces of code that differ only in the comparison direction, use a function from operators to parameterize the comparison.

I had the same question when trying to build a module for unknown ML models. Some require a minimum score to perform, others a maximum score, depending on the metric used. I passed in a 'greater than' boolean variable and wrote a small function:

def is_better(gt,a,b): 
    return a>b if gt else a<b

I would not refactor this by making the operators dynamic in any way. I think the comparisons aren't that similar and forcing them to look more similar obfuscates the code. It's a bit of a red herring.

I would put the complex checks in a function, something like

def customer_trained_enough(customer_info):
    return (
        customer_info['total_dls'] < min_training_actions
        or customer_info['percentage'] > train_perc_cutoff)

def customer_tested_enough(test_info):
    return test_info['total_dls'] >= min_testing_actions

def percentage_too_high(test_info):
    return test_info['percentage'] > test_perc_cutoff

And then the code becomes:

if customer_trained_enough(customer_info):
    continue
if (customer_id not in test_set or
    not customer_tested_enough(test_set[customer_id])):
    num_uncertain += 1
elif not percentage_too_high(test_set[customer_id]):
    num_correct += 1
      else:
    num_incorrect += 1

I guessed some names for the functions, and had to negate the logic in two of them to make the names work.

For some simple cases inverting the inputs sign can be the best approach. It does not require any develop process, just calling the function with opposite sign inputs:

a = 3
b = 5
def func(a,b):
    return a>b

func(a, b) -> False
func(-b, -a) -> True

This approach is equivalent to permute >, <, >=, <= and max, min which is also usually useful because if you are inverting the signs "greater than" and "less that" you may also want to invert the maximum and the minimum for consistency.

The big caveat of this approach is that complex functions can lead to incorrect results, if for instance the functions has middle step involving a mathematical operation such as exponentiation.

Other approach that doesn't suffer from the problem described is using a flag in the comparisons you want to invert, and maybe redefine the max/min function according to it too:

def func(a,b, rev=False):
    rev = -1 if rev else 1
    return rev*a>rev*b

func(a, b) -> False
func(a, b, True) -> True

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM