在Python中为何要使用except:

4 投票
5 回答
2452 浏览
提问于 2025-04-17 22:19

在Python中,使用 except Exception as exexcept BaseException as ex 是不是和 except: 一样,只不过你可以得到一个异常的引用呢?

根据我的理解,BaseException 是一个更新的默认捕获所有异常的方式。

除了这个,为什么你还会想要单独使用 except: 这个语句呢?

5 个回答

0

除了这个,为什么你会想要单独使用一个 except: 语句呢?

简单来说:你其实不需要这样做。

详细说说:如果你只用一个简单的 except:,就没法区分不同的错误了。而且,想要获取错误的具体信息也会变得更困难。所以通常我们会使用 except ExceptionType as e: 这种写法。

2

其实不是这样的。

如果你去看看Python的文档,特别是关于内置异常的部分(可以参考这一块),你会看到各种异常是从哪里继承来的。如果你用原始的except:,它会捕捉到所有抛出的异常,包括KeyboardInterrupt(也就是你按下Ctrl+C时的中断),这通常是你不想捕捉的;如果你用except BaseException as exp:,同样的情况也会发生,因为所有异常都是从它继承的。

如果你想捕捉所有程序运行时的异常,正确的做法是用except Exception as exp:,这样就不会捕捉到那些你希望程序结束时抛出的异常(比如KeyboardInterrupt)。

现在,有人会告诉你这样捕捉所有异常是个坏主意,通常他们是对的;不过如果你有一个程序在处理大量数据时,你可能希望它在遇到异常时不要直接退出。只要你妥善处理这些异常(比如记录下来,并确保用户知道发生了异常),但绝对不要只是用pass跳过;如果你的程序出现了你不知道的错误,它可能会表现得非常奇怪!

3

如果你真的不在乎失败的原因或错误信息,你可以用一个简单的 except:。有时候,这样做是有用的,比如你想使用一些可能存在也可能不工作的功能。如果它失败了,你打算优雅地转向其他的代码路径。在这种情况下,错误的类型或信息对你接下来要做的事情没有影响。

5

除了“宝可梦”异常处理*是个坏主意之外,还有几个不同之处。

在Python 2中,except Exception:except BaseException:都无法捕获旧式类异常:

>>> class Foo(): pass
... 
>>> try:
...     raise Foo()
... except Exception:
...     print 'Caught'
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
__main__.Foo: <__main__.Foo instance at 0x10ef566c8>
>>> try:
...     raise Foo()
... except BaseException:
...     print 'Caught'
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
__main__.Foo: <__main__.Foo instance at 0x10ef56680>
>>> try:
...     raise Foo()
... except:
...     print 'Caught'
... 
Caught

这是因为旧式对象并不是从BaseExceptionException派生的。因此,任何情况下都不应该使用不从Exception派生的自定义异常。

接下来,有三个异常是从BaseException派生的,但不是从Exception派生的;在大多数情况下,你不想捕获这些异常。SystemExitKeyboardInterruptGeneratorExit这些异常在正常的异常处理过程中通常是不需要捕获的。如果你使用except BaseException:,你会捕获到这些异常,而except Exception则不会。


* “宝可梦”异常处理是因为你必须“捕获所有”。

5

这三者之间的区别是:

  1. 光秃秃的 except 会捕捉到所有东西,包括像 KeyboardInterrupt 这样的系统退出事件;
  2. except Exception[ as ex] 会捕捉到任何 Exception 的子类,这应该包括你自己定义的所有异常和 所有内置的非系统退出异常
  3. except BaseException[ as ex] 和光秃秃的 except 一样,会捕捉到绝对所有的异常。

一般来说,我建议使用第二种方式(理想情况下是在捕捉到特定的“预期”错误后作为备用),因为这样可以让那些系统退出的异常上升到更高的层级。正如你所说,第二和第三种方式中的 as ex 部分让你在处理错误时可以检查这个错误。

这里有一篇关于“except 的坏处”的有用文章,点击这里可以查看。

撰写回答