我有一个方法,按顺序调用其他4个方法来检查特定的条件,并立即返回(不检查以下那些)每当一个返回一些真理。

def check_all_conditions():
    x = check_size()
    if x:
        return x

    x = check_color()
    if x:
        return x

    x = check_tone()
    if x:
        return x

    x = check_flavor()
    if x:
        return x
    return None

这似乎是一大堆行李规定。而不是每个2行if语句,我宁愿这样做:

x and return x

但这是无效的Python。我是不是错过了一个简单、优雅的解决方案?顺便说一句,在这种情况下,这四个检查方法可能代价很高,所以我不想多次调用它们。


当前回答

上面的Martijns的第一个例子略有变化,避免了循环中的if:

Status = None
for c in [check_size, check_color, check_tone, check_flavor]:
  Status = Status or c();
return Status

其他回答

我很惊讶没有人提到内置的任何是为了这个目的:

def check_all_conditions():
    return any([
        check_size(),
        check_color(),
        check_tone(),
        check_flavor()
    ])

注意,尽管这个实现可能是最清晰的,但它计算所有的检查,即使第一个检查为True。


如果你真的需要在第一次检查失败时停止,考虑使用reduce来将一个列表转换为一个简单的值:

def check_all_conditions():
    checks = [check_size, check_color, check_tone, check_flavor]
    return reduce(lambda a, f: a or f(), checks, False)

reduce(function, iterable[, initializer]):应用2的函数 参数从左到右累加到iterable的项, 从而将可迭代对象减少为单个值。左边的参数x, 累积值和正确的参数y是否更新 值。如果存在可选初始化式,则为 在计算中置于可迭代对象的项之前

在你的情况下:

lambda a, f: a或f()是检查累加器a或当前检查f()是否为True的函数。注意,如果a为True, f()将不会被求值。 检查包含检查函数(来自lambda的f项) False是初始值,否则不会发生检查,结果总是True

Any和reduce是函数式编程的基本工具。我强烈建议你训练这些以及地图,这是很棒的!

如果你想要相同的代码结构,你可以使用三元语句!

def check_all_conditions():
    x = check_size()
    x = x if x else check_color()
    x = x if x else check_tone()
    x = x if x else check_flavor()

    return x if x else None

我觉得这看起来很清晰。

演示:

我喜欢@timgeb的。与此同时,我想补充的是,在返回语句中表达None是不需要的,因为计算语句的集合或分离语句,并且返回第一个非零,非空,无-None,如果没有,则返回None,无论是否有None !

所以我的check_all_conditions()函数看起来像这样:

def check_all_conditions():
    return check_size() or check_color() or check_tone() or check_flavor()

使用timeit和number=10**7,我查看了一些建议的运行时间。为了便于比较,我只是使用random.random()函数返回一个基于随机数的字符串或None。以下是整个代码:

import random
import timeit

def check_size():
    if random.random() < 0.25: return "BIG"

def check_color():
    if random.random() < 0.25: return "RED"

def check_tone():
    if random.random() < 0.25: return "SOFT"

def check_flavor():
    if random.random() < 0.25: return "SWEET"

def check_all_conditions_Bernard():
    x = check_size()
    if x:
        return x

    x = check_color()
    if x:
        return x

    x = check_tone()
    if x:
        return x

    x = check_flavor()
    if x:
        return x
    return None

def check_all_Martijn_Pieters():
    conditions = (check_size, check_color, check_tone, check_flavor)
    for condition in conditions:
        result = condition()
        if result:
            return result

def check_all_conditions_timgeb():
    return check_size() or check_color() or check_tone() or check_flavor() or None

def check_all_conditions_Reza():
    return check_size() or check_color() or check_tone() or check_flavor()

def check_all_conditions_Phinet():
    x = check_size()
    x = x if x else check_color()
    x = x if x else check_tone()
    x = x if x else check_flavor()

    return x if x else None

def all_conditions():
    yield check_size()
    yield check_color()
    yield check_tone()
    yield check_flavor()

def check_all_conditions_Phil_Frost():
    for condition in all_conditions():
        if condition:
            return condition

def main():
    num = 10000000
    random.seed(20)
    print("Bernard:", timeit.timeit('check_all_conditions_Bernard()', 'from __main__ import check_all_conditions_Bernard', number=num))
    random.seed(20)
    print("Martijn Pieters:", timeit.timeit('check_all_Martijn_Pieters()', 'from __main__ import check_all_Martijn_Pieters', number=num))
    random.seed(20)
    print("timgeb:", timeit.timeit('check_all_conditions_timgeb()', 'from __main__ import check_all_conditions_timgeb', number=num))
    random.seed(20)
    print("Reza:", timeit.timeit('check_all_conditions_Reza()', 'from __main__ import check_all_conditions_Reza', number=num))
    random.seed(20)
    print("Phinet:", timeit.timeit('check_all_conditions_Phinet()', 'from __main__ import check_all_conditions_Phinet', number=num))
    random.seed(20)
    print("Phil Frost:", timeit.timeit('check_all_conditions_Phil_Frost()', 'from __main__ import check_all_conditions_Phil_Frost', number=num))

if __name__ == '__main__':
    main()

结果如下:

Bernard: 7.398444877040768
Martijn Pieters: 8.506569201346597
timgeb: 7.244275416364456
Reza: 6.982133448743038
Phinet: 7.925932800076634
Phil Frost: 11.924794811353031

对我来说,最好的答案是@ phill -frost,然后是@wayne-werner's。

我发现有趣的是,没有人说过一个函数将返回许多不同的数据类型,这将强制检查x本身的类型来做任何进一步的工作。

所以我会将@PhilFrost的回答与保持单一类型的想法混合在一起:

def all_conditions(x):
    yield check_size(x)
    yield check_color(x)
    yield check_tone(x)
    yield check_flavor(x)

def assessed_x(x,func=all_conditions):
    for condition in func(x):
        if condition:
            return x
    return None

注意,x被作为一个参数传递,但all_conditions也被用作检查函数的传递生成器,其中所有检查函数都得到一个要检查的x,并返回True或False。通过使用带有all_conditions作为默认值的func,您可以使用assessed_x(x),或者您可以通过func传递进一步的个性化生成器。

这样,只要一个检查通过,您就会得到x,但它总是相同的类型。

除了马丁的好答案,你还可以用链条或者。这将返回第一个真值,如果没有真值,则返回None:

def check_all_conditions():
    return check_size() or check_color() or check_tone() or check_flavor() or None

演示:

>>> x = [] or 0 or {} or -1 or None
>>> x
-1
>>> x = [] or 0 or {} or '' or None
>>> x is None
True