我有一个函数,按优先顺序返回几个组的随机成员。它是这样的:
def get_random_foo_or_bar():
"I'd rather have a foo than a bar."
if there_are_foos():
return get_random_foo()
if there_are_bars():
return get_random_bar()
raise IndexError, "No foos, no bars"
但是,get_random_foo
做的第一件事就是验证是否存在foos并提升IndexError
,如果没有,那么there_are_foos
就是多余的。此外,涉及数据库并使用单独的函数会产生并发问题。因此,我重写了这样的事情:
def get_random_foo_or_bar():
"Still prefer foos."
try:
return get_random_foo()
except IndexError:
pass
try:
return get_random_bar()
except IndexError:
pass
raise IndexError, "No foos, no bars"
但是我觉得这个可读性要低得多,因为我觉得在感到错误之前我没有理由使用pass
。
是否有更整洁的有效模式,或者我应该学会接受pass
?
注意:我想避免任何嵌套,因为稍后可能会添加其他类型。
修改
感谢所有说pass
没事的人 - 这让人放心!
还要感谢那些建议用返回值None
替换异常的人。我可以看到这是一个有用的模式,但我认为在这种情况下它在语义上是错误的:已经要求函数执行一个不可能完成的任务,因此它们应该引发异常。我更喜欢遵循random
模块的行为(例如random.choice([])
)。
答案 0 :(得分:13)
这正是我写它的方式。这很简单,也很有道理。我认为pass
语句没有问题。
如果您想减少重复次数并且预计会添加未来类型,则可以将其转换为循环。然后,您可以将pass
更改为功能相当的continue
语句,如果这更令您满意:
for getter in (get_random_foo, get_random_bar):
try:
return getter()
except IndexError:
continue # Ignore the exception and try the next type.
raise IndexError, "No foos, no bars"
答案 1 :(得分:2)
pass
没问题(原因它在语言中! - ),但是无通道替代方案只需要更多嵌套:
try: return get_random_foo()
except IndexError:
try: return get_random_bar()
except IndexError:
raise IndexError "no foos, no bars"
Python的Zen(来自交互式解释器提示符的import this
)说“flat比嵌套更好”,但是嵌套在语言中也是 ,供你在决定时使用(推测)被开悟了,你可以做得比那更明智的公主更好! - )(如同,“如果你在路上遇见佛陀......”)。
答案 2 :(得分:2)
get_random_foo()
当它没有将索引作为参数(但在上下文中可能更有意义)时,get_random_foo()
引发了一个IndexError,这看起来有点奇怪。为什么不让def get_random_foo_wrapper():
try:
return get_random_foo()
except IndexError:
return None
def get_random_foo_or_bar():
"I'd rather have a foo than a bar."
return get_random_foo_wrapper() or get_random_bar_wrapper() or None
或包装器捕获错误并返回None?
or
编辑:我应该提一下,如果foo& bar是可以评估为False(0或'')的对象,然后{{1}}比较将跳过它们,这是不好的
答案 3 :(得分:1)
如果只是那两个,可能总是......
try:
return get_random_foo()
except IndexError:
try:
return get_random_bar()
except IndexError:
raise IndexError, "No foos, no bars"
如果它超过两个,你所写的内容似乎完全可以接受。
答案 4 :(得分:1)
除try以外,可以使用try,但是有一种更干净的方法可以使用contextlib.suppress()
来编写此代码,该版本可用于python 3.4 +。
from contextlib import suppress
def get_random_foo_or_bar():
"Still prefer foos."
with suppress(IndexError):
return get_random_foo()
with suppress(IndexError):
return get_random_bar()
raise IndexError("No foos, no bars")
答案 5 :(得分:0)
根据Peter Gibson的建议,您可以创建一个吞噬给定异常的通用包装函数。然后你可以编写一个函数,返回这样的通用包装器,用于提供的异常。或者,对于提供的列表例外情况。
def maketrap(*exceptions):
def trap(func, *args, **kwargs):
try:
return func(*args, **kwargs)
except exceptions:
return None
return trap
def get_random_foo_or_bar():
mytrap = maketrap(IndexError)
return mytrap(get_random_foo) or mytrap(get_random_bar) or None
答案 6 :(得分:0)
如果你真的不需要异常消息(只是类型):
def get_random_foo_or_bar():
try:
return get_random_foo()
except IndexError:
return get_random_bar() # if failing at this point,
# the whole function will raise IndexError
答案 7 :(得分:0)
如果它无法成功,get_random_foo / bar()是否需要引发IndexError?
如果他们返回None,你可以这样做:
def get_random_foo_or_bar():
return get_random_foo() or get_random_bar()