我有一个方法,按顺序调用其他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。我是不是错过了一个简单、优雅的解决方案?顺便说一句,在这种情况下,这四个检查方法可能代价很高,所以我不想多次调用它们。


当前回答

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

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

我觉得这看起来很清晰。

演示:

其他回答

你可以使用循环:

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

这样做还有一个额外的好处,那就是您现在可以使条件的数量可变。

你可以使用map() + filter() (Python 3版本,使用Python 2中的future_builtins版本)来获得第一个这样的匹配值:

try:
    # Python 2
    from future_builtins import map, filter
except ImportError:
    # Python 3
    pass

conditions = (check_size, check_color, check_tone, check_flavor)
return next(filter(None, map(lambda f: f(), conditions)), None)

但这是否更具可读性还有待商榷。

另一种选择是使用生成器表达式:

conditions = (check_size, check_color, check_tone, check_flavor)
checks = (condition() for condition in conditions)
return next((check for check in checks if check), None)

除了马丁的好答案,你还可以用链条或者。这将返回第一个真值,如果没有真值,则返回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

根据Curly定律,你可以通过拆分两个关注点来提高代码的可读性:

我要检查哪些东西? 有一件事是真的吗?

分为两个功能:

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

def check_all_conditions():
    for condition in all_conditions():
        if condition:
            return condition
    return None

这避免了:

复杂的逻辑结构 非常长的队伍 重复

...同时保留一个线性的,易于阅读的流。

根据您的特定情况,您可能还可以提出更好的函数名称,使其更具可读性。

python的方法是使用reduce(有人已经提到过)或itertools(如下所示),但在我看来,简单地使用或操作符的短路可以产生更清晰的代码

from itertools import imap, dropwhile

def check_all_conditions():
    conditions = (check_size,\
        check_color,\
        check_tone,\
        check_flavor)
    results_gen = dropwhile(lambda x:not x, imap(lambda check:check(), conditions))
    try:
        return results_gen.next()
    except StopIteration:
        return None

对我来说,最好的答案是@ 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,但它总是相同的类型。