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
返回适当的异常消息。