避免多层比较函数中的重复

Avoiding repetition in a multi-tiered comparison function

提问人:Charles 提问时间:7/12/2023 更新时间:7/12/2023 访问量:88

问:

我有一个比较函数,看起来像这样:

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))
  # ...

但当然,这是行不通的,因为内部函数无法将值返回给外部函数。我可以使用异常或标志,但这看起来很糟糕。由于每种情况下的结构都是相同的,因此我想避免每次都重复自己,有什么建议吗?

python-3.x 比较

评论

0赞 Jemshit 7/12/2023
相关新闻: stackoverflow.com/questions/72535351/...
0赞 Linux 7/12/2023
您可以在开始时定义并返回所需的值。在里面,当你需要时,只需调用该函数:.inner_compare(z)compare()compared_data=inner_compare(z)

答:

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。signstmp

此时应包含 1 和 -1 的交替模式。如果没有,则返回 0。tmp

pair_sums:应该是 0 的列表。

remains:如果非空则包含具有相同值的相邻元素,则返回 0;否则返回 1。tmp

评论

0赞 fakedad 7/12/2023
需要注意的一个小细节 - 如果 和 是可以溢出的类型(例如,numpy 的类型),并不是检查是否具有相同符号的可靠方法。currenttmpnp.int8current * tmp > 0currenttmp
0赞 Charles 7/12/2023
@fakedad 总的来说,这绝对是值得注意的,但在我的情况下,乘法不会溢出。
0赞 Charles 7/12/2023
所以你的建议是每次都重复(简化的)代码块?是的,我第一次可以分配。
0赞 Cherry Coke 7/12/2023
是的,重复从赋值开始的代码块。从你的代码中,我假设你要对函数进行惰性评估。如果没有,那么第二次尝试应该可以解决@fakedad警告。tmp