如何设计Python中“sifter”行为的控制流?

时间:2022-01-11 21:26:01

Say there's a kind of function that returns either some value or None, and we have three such functions: egg, ham and spam.

假设有一种函数返回某个值或None,我们有三个这样的函数:egg,ham和spam。

The goal is to call egg, ham, spam and return the first non-None value returned, and if there's no valid value return, return None.

目标是调用egg,ham,spam并返回返回的第一个非None值,如果没有有效值返回,则返回None。

The most straightforward way would be:

最直接的方式是:

def func():
    ret = egg()
    if ret:
        return ret
    ret = ham()
    if ret:
        return ret
    ret = spam()
    if ret:
        return ret
    return None

or, a smarter but maybe harder to read solution is:

或者,更聪明但可能更难阅读的解决方案是:

def func():
    return egg() or ham() or spam()

Here're my questions (there could be more than three candidate functions to call):

这是我的问题(可能有三个以上的候选函数要调用):

  1. Is the second way hard to read and should be avoided?
  2. 第二种方式难以阅读且应该避免吗?

  3. Is there a better way to design such control flow? I remember there's something in Lisp that does exactly this, but what about in Python?
  4. 有没有更好的方法来设计这样的控制流程?我记得在Lisp中有一些东西可以做到这一点,但在Python中呢?

2 个解决方案

#1


0  

Something like:

def sifter():
  funcs = [eggs, ham, spam]
  result = None
  while funcs and result is None:
    result = funcs.pop(0)()
  return result

A little explanation: assuming, as in the question, that all the functions to run accept no arguments the while funcs and result is None bit ensures there are more functions to try and that the current result is still None. in the while loop we:

一个小解释:假设,如问题所示,所有要运行的函数都不接受参数,而funcs和结果是None位确保有更多的函数要尝试,并且当前结果仍然是None。在while循环中我们:

  1. Pop the first item from the list of funcs funcs.pop(0). (The list of funcs then looses that func)
  2. 弹出funcs funcs.pop(0)列表中的第一项。 (函数列表然后失去那个函数)

  3. call the poped function ()
  4. 调用poped函数()

  5. Assign what is returned from the function call to the name result =
  6. 将函数调用返回的内容分配给名称result =

Ready for the next loop through the while statement.

准备好通过while语句进行下一个循环。

#2


0  

As this requirement is very similar to the builtin any() I would write:

因为这个要求非常类似于内置的any()我会写:

def anyval(iterable):
    r = None
    for r in iterable:
        if callable(r):
            r = r()
        if r != None:
            break
    return r


def foo():
    return None

def bar():
    return 0

def baz(x):
    return x * 3.14

print(anyval([None,foo,bar]))
print(anyval([None,lambda: baz(3.14)]))

#1


0  

Something like:

def sifter():
  funcs = [eggs, ham, spam]
  result = None
  while funcs and result is None:
    result = funcs.pop(0)()
  return result

A little explanation: assuming, as in the question, that all the functions to run accept no arguments the while funcs and result is None bit ensures there are more functions to try and that the current result is still None. in the while loop we:

一个小解释:假设,如问题所示,所有要运行的函数都不接受参数,而funcs和结果是None位确保有更多的函数要尝试,并且当前结果仍然是None。在while循环中我们:

  1. Pop the first item from the list of funcs funcs.pop(0). (The list of funcs then looses that func)
  2. 弹出funcs funcs.pop(0)列表中的第一项。 (函数列表然后失去那个函数)

  3. call the poped function ()
  4. 调用poped函数()

  5. Assign what is returned from the function call to the name result =
  6. 将函数调用返回的内容分配给名称result =

Ready for the next loop through the while statement.

准备好通过while语句进行下一个循环。

#2


0  

As this requirement is very similar to the builtin any() I would write:

因为这个要求非常类似于内置的any()我会写:

def anyval(iterable):
    r = None
    for r in iterable:
        if callable(r):
            r = r()
        if r != None:
            break
    return r


def foo():
    return None

def bar():
    return 0

def baz(x):
    return x * 3.14

print(anyval([None,foo,bar]))
print(anyval([None,lambda: baz(3.14)]))