有没有比`except: pass`更优雅的替代方案?

7 投票
8 回答
18346 浏览
提问于 2025-04-16 04:12

我有一个函数,它会根据优先顺序随机返回几个组中的一个成员。大概是这样的:

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 个回答

2

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 可以看到)提到“扁平结构比嵌套结构更好”,但嵌套结构也是这个语言的一部分,你可以在觉得自己有更好的解决方案时使用它(大概是你领悟到了什么!)。就像那句“如果你在路上遇到佛祖……”一样。

6

使用 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")
14

这正是我会写的方式。它简单明了,我觉得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"

撰写回答