特殊的 KeyboardInterrupt
日常代码中,我们经常会遇到一些程序运行错误,比如整数除零,比如字符串转浮点型错误。特别在 Python 这种灵活的脚本语言中,由于函数不限制输入类型,我们经常会遇到 caller 不熟悉函数内部逻辑,输入参数属性错误导致的程序问题。这时候为了程序可以稳健运行,在函数内部包一层
try .. except
保护逻辑是一种常见的做法。# try-except example def my_function(): try: # do some real processing ... except Exception as _excp: # handle exception ...
但是,
KeyboardInterrupt
虽然也是一种 exception,但它却不能被这种方法捕获。同样的还有SystemExit
和GeneratorExit
。主要原因是,这三个类事实上都不是继承自Exception
类,而是属于更上一层的BaseException
类。至于为什么 Python 会这么设计,我们先来看看这哥们三都是在什么条件下产生的。首先是
KeyboardInterrupt
,这个大家应该都很熟悉。在 Linux 环境下,会在你在终端按下 ctr+c
的时候产生,或者准确来说,会在 Python 程序收到 SIGINT
信号的时候产生。主要用于告诉运行程序,你该停下来了。而
SystemExit
,这个 exception 会在调用sys.exit()
的时候产生,用途也是告诉程序是时候退出了,并且可以指定 exit code。也就是说,下面的这两个函数其实是等价的:def raise_with_sys(): import sys sys.exit(12) def direct_raise(): raise SystemExit(12)
至于
GeneratorExit
,这个 exception 比较新,是跟着协程一起推出的,主要标识着一个协程的退出。综上所述,可以看到这三种 exceptions 都不是典型的运行错误,更多是归类于程序控制逻辑的。所以为了防止用户在使用 try-caught 模式的时候不小心把这些程序的控制逻辑给捕获了,Python 把这三类 exceptions 设计成直接继承自
BaseException
而不是Exception
。附录
完整的 Python built-in exceptions 以及其继承关系如下(
python 3.7
):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