有没有比`except: pass`更优雅的替代方案?
我有一个函数,它会根据优先顺序随机返回几个组中的一个成员。大概是这样的:
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
首先会检查是否有可用的成员,如果没有就会抛出一个 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([])
)。
8 个回答
pass
这个关键词是可以用的(它在语言中存在是有原因的!),不过如果你想要一个不使用 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
可以看到)提到“扁平结构比嵌套结构更好”,但嵌套结构也是这个语言的一部分,你可以在觉得自己有更好的解决方案时使用它(大概是你领悟到了什么!)。就像那句“如果你在路上遇到佛祖……”一样。
使用 try、except 和 pass 是可以的,但有一种更简洁的写法,可以用 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")
这正是我会写的方式。它简单明了,我觉得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"