问题:避免“ if x:return x”语句的Python方法

我有一个方法可以依次调用其他4种方法来检查特定条件,并且每当一个方法返回Truthy时立即返回(不检查以下方法)。

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。我在这里错过了一个简单,优雅的解决方案吗?顺便说一句,在这种情况下,这四种检查方法可能很昂贵,因此我不想多次调用它们。

I have a method that calls 4 other methods in sequence to check for specific conditions, and returns immediately (not checking the following ones) whenever one returns something Truthy.

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

This seems like a lot of baggage code. Instead of each 2-line if statement, I’d rather do something like:

x and return x

But that is invalid Python. Am I missing a simple, elegant solution here? Incidentally, in this situation, those four check methods may be expensive, so I do not want to call them multiple times.


回答 0

您可以使用循环:

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)

但是,如果更具可读性,则值得商bat。

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

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)

You could use a loop:

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

This has the added advantage that you can now make the number of conditions variable.

You could use map() + filter() (the Python 3 versions, use the future_builtins versions in Python 2) to get the first such matching value:

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)

but if this is more readable is debatable.

Another option is to use a generator expression:

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)

回答 1

除了Martijn的好答案之外,您还可以连锁or。这将返回第一个真实值,或者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

Alternatively to Martijn’s fine answer, you could chain or. This will return the first truthy value, or None if there’s no truthy value:

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

Demo:

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

回答 2

不要改变

如其他答案所示,还有其他方法可以做到这一点。没有一个像您的原始代码一样清晰。

Don’t change it

There are other ways of doing this as the various other answers show. None are as clear as your original code.


回答 3

实际上,与timgeb的答案相同,但是您可以使用括号进行更好的格式化:

def check_all_the_things():
    return (
        one()
        or two()
        or five()
        or three()
        or None
    )

In effectively the same answer as timgeb, but you could use parenthesis for nicer formatting:

def check_all_the_things():
    return (
        one()
        or two()
        or five()
        or three()
        or None
    )

回答 4

根据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

这样可以避免:

  • 复杂的逻辑结构
  • 真的很长
  • 重复

…同时保持线性,易于阅读的流程。

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

According to Curly’s law, you can make this code more readable by splitting two concerns:

  • What things do I check?
  • Has one thing returned true?

into two functions:

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

This avoids:

  • complicated logical structures
  • really long lines
  • repetition

…while preserving a linear, easy to read flow.

You can probably also come up with even better function names, according to your particular circumstance, which make it even more readable.


回答 5

这是Martijns第一个示例的变体。它还使用“可调用集合”样式以允许发生短路。

可以使用内置功能来代替循环any

conditions = (check_size, check_color, check_tone, check_flavor)
return any(condition() for condition in conditions) 

请注意,此方法any返回一个布尔值,因此,如果您需要支票的确切返回值,则此解决方案将不起作用。any不会区分14'red''sharp''spicy'作为返回值,将他们全部返回True

This is a variant of Martijns first example. It also uses the “collection of callables”-style in order to allow short-circuiting.

Instead of a loop you can use the builtin any.

conditions = (check_size, check_color, check_tone, check_flavor)
return any(condition() for condition in conditions) 

Note that any returns a boolean, so if you need the exact return value of the check, this solution will not work. any will not distinguish between 14, 'red', 'sharp', 'spicy' as return values, they will all be returned as True.


回答 6

您是否考虑过只写if x: return x一行?

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

这与您所做的一样,没有什么重复,但是IMNSHO它的读起来相当流畅。

Have you considered just writing if x: return x all on one line?

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

This isn’t any less repetitive than what you had, but IMNSHO it reads quite a bit smoother.


回答 7

我很惊讶没有人提到any为此目的而设计的内置功能:

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]):将两个参数的函数从左到右累计应用于iterable的项目,以将iterable减少为单个值。左参数x是累加值,右参数y是可迭代对象的更新值。如果存在可选的初始化程序,则将其放置在计算中可迭代项的前面

在您的情况下:

  • lambda a, f: a or f()是用于检查累加器a或当前检查f()是否为的函数True。请注意,如果aTruef()则不会进行评估。
  • checks包含检查功能(flambda中的项目)
  • False 是初始值,否则将不进行检查并且结果始终为 True

anyreduce对于函数式编程的基本工具。我强烈建议您训练这些技巧,以及map哪些也很棒!

I’m quite surprised nobody mentioned the built-in any which is made for this purpose:

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

Note that although this implementation is probably the clearest, it evaluates all the checks even if the first one is True.


If you really need to stop at the first failed check, consider using reduce which is made to convert a list to a simple value:

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]) : Apply function of two arguments cumulatively to the items of iterable, from left to right, so as to reduce the iterable to a single value. The left argument, x, is the accumulated value and the right argument, y, is the update value from the iterable. If the optional initializer is present, it is placed before the items of the iterable in the calculation

In your case:

  • lambda a, f: a or f() is the function that checks that either the accumulator a or the current check f() is True. Note that if a is True, f() won’t be evaluated.
  • checks contains check functions (the f item from the lambda)
  • False is the initial value, otherwise no check would happen and the result would always be True

any and reduce are basic tools for functional programming. I strongly encourage you to train these out as well as map which is awesome too!


回答 8

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

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

我认为,如果您仔细看,这看起来很好看。

演示:

正在运行的屏幕截图

If you want the same code structure, you could use ternary statements!

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

I think this looks nice and clear if you look at it.

Demo:

Screenshot of it running


回答 9

对我来说,最好的答案是@ phil-frost,其次是@ wayne-werner。

我发现有趣的是,没有人说过一个函数将返回许多不同数据类型这一事实,这将使然后必须对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将被检查,然后返回TrueFalse。通过使用funcwith all_conditions作为默认值,您可以使用assessed_x(x),也可以通过传递进一步的个性化生成器func

这样一来,您x就可以通过一次支票,但是它将始终是同一类型。

For me, the best answer is that from @phil-frost, followed by @wayne-werner’s.

What I find interesting is that no one has said anything about the fact that a function will be returning many different data types, which will make then mandatory to do checks on the type of x itself to do any further work.

So I would mix @PhilFrost’s response with the idea of keeping a single type:

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

Notice that x is passed as an argument, but also all_conditions is used as a passed generator of checking functions where all of them get an x to be checked, and return True or False. By using func with all_conditions as default value, you can use assessed_x(x), or you can pass a further personalised generator via func.

That way, you get x as soon as one check passes, but it will always be the same type.


回答 10

理想情况下,我将重写check_ 函数以返回True或返回False值。然后您的支票变成

if check_size(x):
    return x
#etc

假设您x不是一成不变的,则您的函数仍可以对其进行修改(尽管他们不能重新分配它)-但是一个被调用的函数check实际上不应进行任何修改。

Ideally, I would re-write the check_ functions to return True or False rather than a value. Your checks then become

if check_size(x):
    return x
#etc

Assuming your x is not immutable, your function can still modify it (although they can’t reassign it) – but a function called check shouldn’t really be modifying it anyway.


回答 11

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

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

A slight variation on Martijns first example above, that avoids the if inside the loop:

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

回答 12

我喜欢@timgeb。在此期间,我想补充一点,表达Nonereturn语句没有必要为收集or分离的语句进行评估,并在第一无为零,无空,则返回无-无,如果没有任何然后None返回是否有None

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

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

使用timeitwith时,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

I like @timgeb’s. In the meantime I would like to add that expressing None in the return statement is not needed as the collection of or separated statements are evaluated and the first none-zero, none-empty, none-None is returned and if there isn’t any then None is returned whether there is a None or not!

So my check_all_conditions() function looks like this:

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

Using timeit with number=10**7 I looked at the running time of a number of the suggestions. For the sake of comparison I just used the random.random() function to return a string or None based on random numbers. Here is the whole code:

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()

And here are the results:

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

回答 13

这种方法有点开箱即用,但是我认为最终结果很简单,易读并且看起来不错。

基本思想是raise当其中一个函数的评估结果为“真”并返回结果时出现异常。这是它的外观:

def check_conditions():
    try:
        assertFalsey(
            check_size,
            check_color,
            check_tone,
            check_flavor)
    except TruthyException as e:
        return e.trigger
    else:
        return None

assertFalsey当一个调用的函数参数评估为真时,您将需要一个引发异常的函数:

def assertFalsey(*funcs):
    for f in funcs:
        o = f()
        if o:
            raise TruthyException(o)

可以修改上述内容,以便也为要评估的功能提供参数。

当然,您将需要TruthyException自身。此异常提供了object触发异常的:

class TruthyException(Exception):
    def __init__(self, obj, *args):
        super().__init__(*args)
        self.trigger = obj

当然,您可以将原始功能转换为更通用的功能:

def get_truthy_condition(*conditions):
    try:
        assertFalsey(*conditions)
    except TruthyException as e:
        return e.trigger
    else:
        return None

result = get_truthy_condition(check_size, check_color, check_tone, check_flavor)

这可能会慢一些,因为您同时使用了一条if语句和一个异常。但是,该异常最多只能处理一次,因此对性能的影响应该很小,除非您希望运行检查并获得True成千上万次的值。

This way is a little bit outside of the box, but I think the end result is simple, readable, and looks nice.

The basic idea is to raise an exception when one of the functions evaluates as truthy, and return the result. Here’s how it might look:

def check_conditions():
    try:
        assertFalsey(
            check_size,
            check_color,
            check_tone,
            check_flavor)
    except TruthyException as e:
        return e.trigger
    else:
        return None

You’ll need a assertFalsey function that raises an exception when one of the called function arguments evaluates as truthy:

def assertFalsey(*funcs):
    for f in funcs:
        o = f()
        if o:
            raise TruthyException(o)

The above could be modified so as to also provide arguments for the functions to be evaluated.

And of course you’ll need the TruthyException itself. This exception provides the object that triggered the exception:

class TruthyException(Exception):
    def __init__(self, obj, *args):
        super().__init__(*args)
        self.trigger = obj

You can turn the original function into something more general, of course:

def get_truthy_condition(*conditions):
    try:
        assertFalsey(*conditions)
    except TruthyException as e:
        return e.trigger
    else:
        return None

result = get_truthy_condition(check_size, check_color, check_tone, check_flavor)

This might be a bit slower because you are using both an if statement and handling an exception. However, the exception is only handled a maximum of one time, so the hit to performance should be minor unless you expect to run the check and get a True value many many thousands of times.


回答 14

pythonic方式是使用reduce(如已经提到的)或itertools(如下所示),但是在我看来,仅使用or运算符的短路会产生更清晰的代码

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

The pythonic way is either using reduce (as someone already mentioned) or itertools (as shown below), but it seems to me that simply using short circuiting of the or operator produces clearer code

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

回答 15

我要跳进这里,从来没有写过Python的任何一行,但是我认为这if x = check_something(): return x是有效的吗?

如果是这样的话:

def check_all_conditions():

    if (x := check_size()): return x
    if (x := check_color()): return x
    if (x := check_tone()): return x
    if (x := check_flavor()): return x

    return None

I’m going to jump in here and have never written a single line of Python, but I assume if x = check_something(): return x is valid?

if so:

def check_all_conditions():

    if (x := check_size()): return x
    if (x := check_color()): return x
    if (x := check_tone()): return x
    if (x := check_flavor()): return x

    return None

回答 16

或使用max

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

Or use max:

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

回答 17

过去,我见过一些用dicts进行switch / case语句的有趣实现,这使我想到了这个答案。使用您提供的示例,您将获得以下内容。(这很疯狂using_complete_sentences_for_function_names,因此check_all_conditions将其重命名为status。请参阅(1))

def status(k = 'a', s = {'a':'b','b':'c','c':'d','d':None}) :
  select = lambda next, test : test if test else next
  d = {'a': lambda : select(s['a'], check_size()  ),
       'b': lambda : select(s['b'], check_color() ),
       'c': lambda : select(s['c'], check_tone()  ),
       'd': lambda : select(s['d'], check_flavor())}
  while k in d : k = d[k]()
  return k

select函数消除了每次调用check_FUNCTION两次的需要,即避免check_FUNCTION() if check_FUNCTION() else next添加另一个函数层。这对于长时间运行的功能很有用。字典中的lambda会延迟其值的执行,直到while循环为止。

作为奖励,您可以修改执行顺序,甚至可以通过更改k和跳过某些测试,s例如k='c',s={'c':'b','b':None}减少测试数量)和颠倒原始处理顺序。

timeit研究员可能讨价还价增加额外的一层或两层堆栈,为字典成本抬头,但你似乎更关心的是代码的可爱的成本。

另外,一个更简单的实现可能如下:

def status(k=check_size) :
  select = lambda next, test : test if test else next
  d = {check_size  : lambda : select(check_color,  check_size()  ),
       check_color : lambda : select(check_tone,   check_color() ),
       check_tone  : lambda : select(check_flavor, check_tone()  ),
       check_flavor: lambda : select(None,         check_flavor())}
  while k in d : k = d[k]()
  return k
  1. 我的意思不是用pep8而是用一个简洁的描述性词代替句子。授予OP可能遵循某些编码约定,使用一些现有代码库或不在乎其代码库中的简洁术语。

I have seen some interesting implementations of switch/case statements with dicts in the past that led me to this answer. Using the example you’ve provided you would get the following. (It’s madness using_complete_sentences_for_function_names, so check_all_conditions is renamed to status. See (1))

def status(k = 'a', s = {'a':'b','b':'c','c':'d','d':None}) :
  select = lambda next, test : test if test else next
  d = {'a': lambda : select(s['a'], check_size()  ),
       'b': lambda : select(s['b'], check_color() ),
       'c': lambda : select(s['c'], check_tone()  ),
       'd': lambda : select(s['d'], check_flavor())}
  while k in d : k = d[k]()
  return k

The select function eliminates the need to call each check_FUNCTION twice i.e. you avoid check_FUNCTION() if check_FUNCTION() else next by adding another function layer. This is useful for long running functions. The lambdas in the dict delay execution of it’s values until the while loop.

As a bonus you may modify the execution order and even skip some of the tests by altering k and s e.g. k='c',s={'c':'b','b':None} reduces the number of tests and reverses the original processing order.

The timeit fellows might haggle over the cost of adding an extra layer or two to the stack and the cost for the dict look up but you seem more concerned with the prettiness of the code.

Alternatively a simpler implementation might be the following :

def status(k=check_size) :
  select = lambda next, test : test if test else next
  d = {check_size  : lambda : select(check_color,  check_size()  ),
       check_color : lambda : select(check_tone,   check_color() ),
       check_tone  : lambda : select(check_flavor, check_tone()  ),
       check_flavor: lambda : select(None,         check_flavor())}
  while k in d : k = d[k]()
  return k
  1. I mean this not in terms of pep8 but in terms of using one concise descriptive word in place of a sentence. Granted the OP may be following some coding convention, working one some existing code base or not care for terse terms in their codebase.

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。