在Python中将“小于”或“大于”比较作为变量
我有一段代码在一个函数里,主要是用来做一些比较的,具体代码如下:
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
有时候我需要进行“大于”的比较,有时候又需要“小于”的比较。其他的代码都是一样的。现在,我可以简单地写两个函数,基本上重复使用同样的代码,但在这之前,我想知道有没有什么简单的方法,可以把比较的方式变成一个变量,这样我就可以用同一段代码,只需传入比较方式作为参数?比如说:compare(var1, var2, polarity)
。我知道我可以自己实现这个,但我想知道在这种情况下有没有什么标准的做法。有没有什么比较“pythonic”的方法是我不知道的?
[编辑] 强调问题中最重要的部分 [/编辑]
4 个回答
在一些简单的情况下,反转输入的符号可能是最好的方法。这种方法不需要任何开发过程,只需用相反符号的输入调用函数即可:
a = 3
b = 5
def func(a,b):
return a>b
func(a, b) -> False
func(-b, -a) -> True
这种方法相当于交换 >, <, >=, <=
以及 max, min
,这通常也很有用,因为如果你反转了“更大于”和“更小于”,你可能也想为了保持一致性而反转最大值和最小值。
这种方法的大问题是,对于复杂的函数,如果函数中有涉及数学运算的中间步骤,比如指数运算,可能会导致错误的结果。
另一种不受上述问题影响的方法是,在你想要反转的比较中使用一个标志,可能还需要根据这个标志重新定义最大值和最小值的函数:
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
我不会通过让操作符变得动态来重构这个代码。我觉得这些比较并不那么相似,强行让它们看起来更相似反而会让代码变得难以理解。这有点像是误导。
我会把复杂的检查放到一个函数里,像这样:
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
然后代码就变成了:
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
我给这些函数猜了一些名字,还得把其中两个的逻辑反转一下,才能让名字合理。
我在尝试为一些不太了解的机器学习模型构建模块时,也遇到了同样的问题。有些模型需要一个最低分数才能正常工作,而有些则需要一个最高分数,这取决于使用的评估标准。我传入了一个“是否大于”的布尔变量,并写了一个小函数:
def is_better(gt,a,b):
return a>b if gt else a<b
你可以使用operator
模块,里面有一些函数可以当作比较运算符来用:
import operator
if foobar:
comp = operator.lt
else:
comp = operator.gt
if comp(spam, eggs):
这段代码会根据foobar
的真假来判断spam
是小于还是大于eggs
。
这正好符合你对将比较作为变量的需求。
我会用这个方法来避免重复代码;如果你有两段代码,只有比较的方向不同,那就可以用operators
里的函数来参数化这个比较。