我经常在其他Stack Overflow问题上看到关于如何不鼓励使用except: pass的评论。这为什么不好呢?有时我不在乎错误是什么,我只想继续写代码。

try:
    something
except:
    pass

为什么使用except: pass块不好?是什么让它变得糟糕?是我传递了一个错误还是我排除了任何错误?


当前回答

简单地说,如果抛出异常或错误,就说明出了问题。这可能不是什么非常错误的事情,但是仅仅为了使用goto语句而创建、抛出和捕获错误和异常并不是一个好主意,而且很少这样做。99%的情况下,都是某个地方出了问题。

问题需要处理。就像在生活中一样,在编程中,如果你把问题放在一边,试着忽略它们,很多时候它们不会自己消失;相反,它们变得越来越大,越来越多。为了防止一个问题在你身上滋生,并在将来再次出现,你要么1)消除它,然后清理混乱,要么2)控制它,然后清理混乱。

忽略异常和错误并让它们保持原样是体验内存泄漏、未完成的数据库连接、不必要的文件权限锁定等的好方法。

在极少数情况下,这个问题是如此微不足道,微不足道,而且——除了需要尝试……Catch block - self-contained,这样就真的没有什么乱七八糟的东西需要清理了。只有在这些情况下,这种最佳实践并不一定适用。根据我的经验,这通常意味着无论代码在做什么,基本上都是微不足道的,可以忽略的,而像重试尝试或特殊消息这样的事情既不值得复杂,也不值得暂停线程。

在我的公司,规则是几乎总是在catch块中做一些事情,如果你什么都不做,那么你必须总是放置一个注释,并给出一个很好的理由。当有事情要做的时候,你绝对不能错过或留下一个空的catch块。

其他回答

执行你的伪代码甚至不会给出任何错误:

try:
    something
except:
    pass

就好像它是一段完全有效的代码,而不是抛出NameError。我希望这不是你想要的。

你至少应该使用except Exception:来避免捕获系统异常,如SystemExit或KeyboardInterrupt。这里是文档链接。

一般来说,您应该显式地定义想要捕获的异常,以避免捕获不想要的异常。您应该知道您忽略了哪些异常。

我正在构建一个将在数据中心运行的应用程序。它不应该生成任何错误或引发任何异常。我的数据中心有一个网络监控系统,其中包括一个SNMP trap接收器。

try:
    main()
except as e:
    log(str(e))
    send_snmp_trap(str(e))
    raise

但是这个加薪不会有任何效果因为它是和任何可能剩下的堆栈的底部。

顺便说一句,这不是万能的灵丹妙药。有一些例外情况是无法被发现的。SNMP不能保证传输。YMMV。

到目前为止提出的所有意见都是有效的。在可能的情况下,您需要指定想要忽略的异常。在可能的情况下,你需要分析导致异常的原因,只忽略你想要忽略的部分,而不是其他部分。如果异常导致应用程序“壮观地崩溃”,那么就这样吧,因为知道意外发生的时间比隐藏问题发生的时间要重要得多。

综上所述,不要将任何编程实践视为至高无上的。这太愚蠢了。总有时间和地点可以执行“忽略所有异常”块。

白痴派拉特的另一个例子是goto运算符的使用。当我还在学校的时候,我们的教授教我们去运算符,只是为了提醒我们永远不能使用它。不要相信人们告诉你xyz永远不应该被使用,也不可能有一个场景它是有用的。总是有的。

为什么“except: pass”是一种糟糕的编程实践? 这为什么不好呢? 试一试: 某物 除了: 通过

这将捕获所有可能的异常,包括GeneratorExit、KeyboardInterrupt和SystemExit——这些异常可能是您不打算捕获的。这和捕获BaseException是一样的。

try:
    something
except BaseException:
    pass

旧版本的文档说:

由于Python中的每个错误都会引发异常,使用except:可以使许多编程错误看起来像运行时问题,从而阻碍调试过程。

Python异常层次结构

如果您捕获了一个父异常类,那么您也捕获了它们的所有子类。只捕获准备处理的异常要优雅得多。

下面是Python 3的异常层次结构——你真的想把它们都捕捉到吗?:

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EOFError
      +-- ImportError
           +-- ModuleNotFoundError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      |    +-- UnboundLocalError
      +-- OSError
      |    +-- BlockingIOError
      |    +-- ChildProcessError
      |    +-- ConnectionError
      |    |    +-- BrokenPipeError
      |    |    +-- ConnectionAbortedError
      |    |    +-- ConnectionRefusedError
      |    |    +-- ConnectionResetError
      |    +-- FileExistsError
      |    +-- FileNotFoundError
      |    +-- InterruptedError
      |    +-- IsADirectoryError
      |    +-- NotADirectoryError
      |    +-- PermissionError
      |    +-- ProcessLookupError
      |    +-- TimeoutError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      |    +-- RecursionError
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
           +-- ResourceWarning

不要这样做

如果你使用这种形式的异常处理:

try:
    something
except: # don't just do a bare except!
    pass

然后你就不能用Ctrl-C来中断你的something块了。您的程序将忽略try代码块中所有可能的异常。

下面是另一个同样有不良行为的例子:

except BaseException as e: # don't do this either - same as bare!
    logging.info(e)

相反,尝试只捕获您知道正在寻找的特定异常。例如,如果你知道你可能会在一个转换中得到一个值错误:

try:
    foo = operation_that_includes_int(foo)
except ValueError as e:
    if fatal_condition(): # You can raise the exception if it's bad,
        logging.info(e)   # but if it's fatal every time,
        raise             # you probably should just not catch it.
    else:                 # Only catch exceptions you are prepared to handle.
        foo = 0           # Here we simply assign foo to 0 and continue. 

用另一个例子进一步解释

您可能会这样做,因为您已经进行了web抓取并得到了一个UnicodeError,但因为您使用了最广泛的异常捕获,您的代码可能有其他基本缺陷,将试图运行到完成,浪费带宽,处理时间,磨损您的设备,耗尽内存,收集垃圾数据等。

如果其他人要求你完成,这样他们就可以依赖你的代码,我理解那种被迫处理所有事情的感觉。但如果你愿意在开发过程中遭遇失败,你就有机会纠正那些偶尔出现的问题,但这将是代价高昂的长期错误。

有了更精确的错误处理,代码就会更加健壮。