我有一个方法,按顺序调用其他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。我是不是错过了一个简单、优雅的解决方案?顺便说一句,在这种情况下,这四个检查方法可能代价很高,所以我不想多次调用它们。
你可以使用循环:
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)
这种方式有点超出框框,但我认为最终结果是简单的,可读的,而且看起来不错。
基本思想是,当其中一个函数求值为真值时引发异常,并返回结果。下面是它的外观:
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本身。这个异常提供了触发异常的对象:
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值。
对我来说,最好的答案是@ 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,但它总是相同的类型。