【问题标题】:Most pythonic way to call a list of functions [closed]调用函数列表的大多数pythonic方式[关闭]
【发布时间】:2019-10-24 20:56:48
【问题描述】:

我有一个函数列表,如下所示:

def foo(a, b):
    # do stuff
    return True # or False

def bar(c):
    # do stuff
    return False # or True

def baz(d, e, f):
    # do stuff
    return True # or False

我想依次调用它们中的每一个,如果前一个返回True,则只进行下一个,如下所示:

if foo(1, 2):
    if bar(3):
        if baz(4, 5, 6):
            print("Success!")

现在,我知道如果我的所有函数都接受相同的参数,我可以这样做:

steps = [foo, bar, baz]
if all(func(*args) for func in steps):
    print("Success!")

因为all 一旦达到False 返回值就会短路。但是,它们并不都接受相同的论点。

实现这一目标的最简洁方法是什么?

编辑:感谢有关压缩 args 的建议。如果每个函数返回一些值,并且我想使用前一个函数的返回值(无论它可能是什么)来决定我是否运行下一个函数,那么更一般的情况呢?每个函数也可能需要一些先前函数的返回值作为参数。

【问题讨论】:

  • 然后执行arguments = [[1, 2], [3], [4, 5]],然后执行all(func(*args) for func, args in zip(steps, arguments))
  • 如果您有参数集列表并将其与函数一起压缩,则可以使用 all 方法的变体。
  • 您的问题正在迅速变得过于广泛,您应该询问您要解决的确切问题
  • 鉴于您的问题已有多个答案,您最好只提出一个新问题
  • 您的编辑使通用解决方案变得困难,可能有太多变化。

标签: python python-3.x


【解决方案1】:

and 运算符也会短路,所以你可以这样做:

if foo(1, 2) and bar(3) and baz(4, 5, 6):
    print("Success")

如果你想要一个更通用的方法,你可以列出一个 lambdas。

steps = [
    lambda: foo(1, 2), 
    lambda: bar(3), 
    lambda: baz(4, 5, 6)
]
if all(f() for f in steps):
    print("Success")

或元组列表:

steps = [
    (foo, (1, 2)), 
    (bar, (3)), 
    (baz, (4, 5, 6))
]
if all(f(*args) for f, args in steps):
    print("Success")

【讨论】:

  • and 对我来说是迄今为止最干净和最简单的......干得好
  • 最后一个例子应该是第一个:)
  • 虽然我已经对此表示赞同,但操作员的编辑会使您的答案(和其他人)无效
【解决方案2】:

像这样使用all

steps = [foo, bar, baz]
arguments = [[1, 2], [3], [4, 5, 6]]
if all(func(*args) for func, args in zip(steps, arguments)):
    print("Success!")

【讨论】:

  • 我不喜欢像这样将函数与参数分开,它们太容易不同步了。
  • 你可以把它们做成一个字典,函数作为键,参数作为值
  • @martineau 修复了它。
  • @Sayse 字典没有排序,如果你想用不同的参数调用同一个函数两次,它就不起作用了。
  • @Barmar 你为什么要告诉大家字典没有排序?它们已经订购了 了。
【解决方案3】:

函数是可散列的对象,因此您可以将它们用作字典的键。

funcs = {
    foo: (1, 2),
    bar: (3,),
    baz: (4, 5, 6),
}

这比单独的函数和参数列表要干净一些,因为它可以防止列表不同步。

现在只需使用all

if all(f(*args) for f, args in funcs.items()):
    print("Success!")

字典在当前版本的 Python (3.8.0) 以及之前的次要版本 (3.7.x) 中排序。如果您使用旧版本的语言 (collections.OrderedDict

如果您想多次调用同一个函数,则此方法不起作用,因为字典键必须是唯一的。在这种情况下,您应该改用对列表:

steps = [
    (foo, (1, 2)),
    (bar, (3,)),
    (baz, (4, 5, 6)),
    (foo, (7, 8)),
]

【讨论】:

  • 字典未排序。
  • 但是这里不保证顺序对吧?
  • @Barmar 它们在 Python >= 3.7 中排序
  • @shmth 在 Python >= 3.7 中保证订单
  • dict 实际上是从 3.6 开始订购的——CPython 在 3.6 中添加了插入顺序,而 PyPy 从 2.7 开始就有了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-06-21
  • 1970-01-01
  • 2014-09-17
  • 1970-01-01
  • 2014-02-05
  • 1970-01-01
  • 2011-03-23
相关资源
最近更新 更多