Python 除了“通过”之外,还有更整洁的选择吗?
我有一个函数,它按优先顺序返回几个组中的一个随机成员。事情是这样的:Python 除了“通过”之外,还有更整洁的选择吗?,python,exception-handling,coding-style,Python,Exception Handling,Coding Style,我有一个函数,它按优先顺序返回几个组中的一个随机成员。事情是这样的: 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 foo
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"
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"
但是,get\u random\u foo
要做的第一件事是验证是否存在foo,如果没有,则提出一个indexer
,因此there\u foo
是多余的。此外,还涉及数据库,使用单独的函数会产生并发问题。因此,我将其改写如下:
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"
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
很好-这让人放心
还感谢那些建议将异常替换为返回值
None
的人。我可以看出这是一个多么有用的模式,但我认为在这种情况下它在语义上是错误的:函数被要求执行一个不可能的任务,所以它们应该引发一个异常。我更喜欢遵循random
模块的行为(例如random.choice([])
)。如果只是这两个模块,那么总是可以
try:
return get_random_foo()
except IndexError:
try:
return get_random_bar()
except IndexError:
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"
pass
很好(它在语言中是有原因的!-),但无pass的替代方案只需要更多的嵌套:
try: return get_random_foo()
except IndexError:
try: return get_random_bar()
except IndexError:
raise IndexError "no foos, no bars"
Python的Zen(
从交互式解释器提示符导入此
)说“扁平比嵌套好”,但嵌套也在语言中,当您决定(可能是开明的)您可以做得比wise koan更好时,您可以使用嵌套!)(如“如果你在路上遇到佛陀”…。我觉得有点奇怪,get\u random\u foo()
在不将索引作为参数的情况下引发索引器(但在上下文中可能更有意义)。为什么不让get\u random\u foo()
或包装器捕获错误并返回None
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
编辑:我应该提到,如果foo和bar是可能计算为False(0或“say”)的对象,那么
或比较将跳过它们,这是不好的基于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
如果您真的不需要异常消息(仅需要类型):
如果get_random_foo/bar()无法成功,是否有必要引发索引器
如果他们没有返回,您可以执行以下操作:
def get_random_foo_or_bar():
return get_random_foo() or get_random_bar()
使用try,except,pass是可以接受的,但是有一种更干净的方法可以使用python3.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")
在except
语句中使用可能是Python中最常用的pass
。所以我会习惯的。“但我觉得这很难理解……这感觉是错误的”——把它看作是一个文化问题。现在看起来很奇怪,但这是最干净的语言使用方式。我从随机模块中得到了提示-尝试运行random.choice([])
。有趣的解决方案,谢谢!我想我更愿意从get\u random\u foo\u或\u bar
明确地提出错误,而不是依赖于恰好相同的错误并需要注释。这也允许我从get\u random\u foo\u或\u bar
返回适当的异常消息。