提问人:Charles 提问时间:7/12/2023 更新时间:7/12/2023 访问量:88
避免多层比较函数中的重复
Avoiding repetition in a multi-tiered comparison function
问:
我有一个比较函数,看起来像这样:
def compare(x, y):
current = 0
tmp = complicated_function(x, y)
if tmp > 0:
if current < 0:
return 0 # incomparable
current = -1
elif tmp < 0:
if current > 0:
return 0 # incomparable
current = 1
tmp = complicated_function_2(x, y)
if tmp > 0:
if current < 0:
return 0 # incomparable
current = -1
elif tmp < 0:
if current > 0:
return 0 # incomparable
current = 1
# ...
return current
基本上,它做了很多比较。如果它们都兼容(0 和 1 的混合、0 和 -1 的混合或所有 0),则返回结果;否则,提前以值 0 结束。
实现这一点的最 Pythonic 方法是什么?我很想做
def compare(x, y):
current = 0
def inner_compare(z):
if z > 0:
if current == -1:
return 0 # <------- fails here
current = 1
if z < 0:
if current == 1:
return 0 # <------- fails here
current = -1
inner_compare(complicated_function(x, y))
inner_compare(complicated_function_2(x, y))
# ...
但当然,这是行不通的,因为内部函数无法将值返回给外部函数。我可以使用异常或标志,但这看起来很糟糕。由于每种情况下的结构都是相同的,因此我想避免每次都重复自己,有什么建议吗?
答:
0赞
jake.csc
7/12/2023
#1
这些之一有帮助吗?如果不是,我可能误解了这个问题。 我假设 (0,0) 返回 1(因为 0 是ends_early信号)
def compare1(x, y):
if x >= 0 and y >= 0:
return 1
if x < 0 and y < 0:
return -1
return 0
#if (0,0) return something different then you can use this function
#just fill #in the last part under if x==0
def compare2(x, y):
if x > 0:
return 0 if y < 0 else 1
if x < 0:
return 0 if y > 0 else -1
if x == 0:
return "something" if y == 0 else "something_else"
return None
0赞
fakedad
7/12/2023
#2
你能循环你的复杂功能吗?这似乎是避免重复自己的直接方法。
complicated_functions = [
complicated_function,
complicated_function_2,
# ...
]
def compare(x, y):
current = 0
for cf in complicated_functions:
tmp = cf(x, y)
if tmp > 0:
if current < 0:
return 0 # incomparable
current = -1
elif tmp < 0:
if current > 0:
return 0 # incomparable
current = 1
# ...
return current
0赞
user2390182
7/12/2023
#3
您可以遍历函数,也可以遍历仅在某些操作数的符号 (, ) 中有所不同的冗余条件。您还可以使用内部函数:+
-
funcs = [comp_func, comp_func_2, ...]
def compare(x, y):
def inner_compare(z):
for sign in (1, -1):
if sign * z > 0:
if sign * current < 0:
return 0 # incomparable
return -1 * sign
current = 0
for cf in funcs:
if (current := inner_compare(cf(x, y))) == 0:
break
return current
0赞
Cherry Coke
7/12/2023
#4
第一次尝试
def compare(x,y):
import math
current = complicated_function(x, y)
tmp = complicated_function_2(x, y)
if current * tmp > 0:
return 0
if tmp:
current = tmp
# ...
return math.copysign(1, -current) if current else 0
第二次尝试
import numpy as np
import itertools as it
def compare(x,y):
signs = np.sign([
complicated_function(x, y),
complicated_function_2(x, y),
...
complicated_function_n(x, y)
])
tmp = [x for x in signs if x != 0]
if len(tmp) == 0:
return 0
pair_sums = list(map(sum, it.pairwise(tmp)))
remains = [x for x in pair_sums if x != 0]
return len(remains) == 0
signs
:每个函数值的符号。
tmp
:从 中筛选出 '0' 值。
如果为空,则返回 0。signs
tmp
此时应包含 1 和 -1 的交替模式。如果没有,则返回 0。tmp
pair_sums
:应该是 0 的列表。
remains
:如果非空则包含具有相同值的相邻元素,则返回 0;否则返回 1。tmp
评论
0赞
fakedad
7/12/2023
需要注意的一个小细节 - 如果 和 是可以溢出的类型(例如,numpy 的类型),并不是检查是否具有相同符号的可靠方法。current
tmp
np.int8
current * tmp > 0
current
tmp
0赞
Charles
7/12/2023
@fakedad 总的来说,这绝对是值得注意的,但在我的情况下,乘法不会溢出。
0赞
Charles
7/12/2023
所以你的建议是每次都重复(简化的)代码块?是的,我第一次可以分配。
0赞
Cherry Coke
7/12/2023
是的,重复从赋值开始的代码块。从你的代码中,我假设你要对函数进行惰性评估。如果没有,那么第二次尝试应该可以解决@fakedad警告。tmp
评论
inner_compare(z)
compare()
compared_data=inner_compare(z)