为什么使用contextlib.suppress而不是try/except与pass结合使用?

67
为什么要使用 contextlib.suppress 来压制异常,而不是用 try/exceptpass
这两种方法的字符数没有区别(如果有区别的话,suppress 字符更多),尽管代码通常按行数计算,但无论何时发生错误或未发生错误,suppress 的速度似乎都比 try/except 慢得多。
Python 3.5.0 (v3.5.0:374f501f4567, Sep 13 2015, 02:27:37) [MSC v.1900 64 bit (AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> from timeit import timeit
>>> # With an error
>>> timeit("""with suppress(ValueError):
    x = int('a')""", setup="from contextlib import suppress")
1.9571568971892543
>>> timeit("""try:
    x = int('a')
except ValueError:
    pass""")
1.0758466499161656
>>> # With no error
>>> timeit("""with suppress(ValueError):
    x = int(3)""", setup="from contextlib import suppress")
0.7513525708063895
>>> timeit("""try:
    x = int(3)
except ValueError:
    pass""")
0.10141028937128027
>>> 

1
它可以节省两行代码。如果您有几个连续的这样的代码块,则它可以大大提高代码的可读性。 - Valentin Lorentz
同样的,为什么要使用any()all(),而不是使用for循环呢?我认为使用contextlib.suppress有助于提高可读性和维护性。 - Simeon Visser
2
@SimeonVisser any()all()显然可以使代码更短,无论是在行数上还是字符数上。我也非常确定any()all()在性能方面比for循环更快。就我所见,使用suppress的唯一原因是它更易读(即使这也是有争议的,因为它需要更多的字符)。另一方面,使用try/except则要快得多。 - Markus Meskanen
1
没错。也许这与采用函数式编程有关(例如,在某些情况下传递 contextlib.suppress 来有条件地抑制异常,而在其他情况下则不抑制)? - Simeon Visser
2个回答

67

不牺牲可读性的情况下,代码行数减少了两行。

对于嵌套或连续的代码块可能特别方便。比较如下:

try:
    a()
    try:
        b()
    except B:
        pass
except A:
    pass

对比:

with suppress(A):
    a()
    with suppress(B):
        b()

它还允许表达意图:

  • with suppress(SpecificError): do_something()表示如果在执行某些操作时发生错误,则不传播该错误
  • try: do_something() except SpecificError: pass表示先执行某些操作,如果发生错误则不传播该错误

这并不是很重要,因为大多数人不会注意到区别。


20

对我而言,就概念来说,contextlib.suppress方法让我能够处理可能会发生的错误(比如试图删除实际上不存在的文件)。然后try/except成为更主动处理“这不应该发生”的事件(比如除以0或无法打开我想要写入的文件)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接