错误、异常和警告
错误
语法错误/解析错误,解释执行前发现,类SyntaxError
.
异常
解释执行时发现的错误,类Exception
,用户可继承该类,定制异常。
异常基类实现了str方法,用来打印异常信息。、
额外知识
异常不是错误,异常甚至不是罕见的,异常是主观的,凡是不符合程序员预期的均可视作异常。
硬件异常 VS 程序异常
异常大致可以分为两种,一种是硬件异常,在程序之外由硬件触发的,如CPU发现除0错误、地址索引违规等,网卡发现数据,硬盘发现IO等,由OS或硬件异常处理机制处理;
另一种是程序异常,是由程序里面的代码主动触发的,比如非法输入、内存分配失败、文件IO错误等,由程序自身或者语言的runtime处理;
硬中断 VS 软中断
两者都是打断当前运行程序,转移控制权(程序指针)到指定内存地址的机制。
主要区别在于触发方和处理方式,硬中断由硬件触发,如鼠标、键盘,处理方式为跳转到指定内存地址(驱动程序),也可能需要硬件处理。
软中断由程序触发,如可通过int汇编指令触发,或者系统调用指令。
中断 VS 信号
中断可以视作CPU和OS之间沟通的手段,可以由CPU触发(页错误,除以零)、硬件设备触发、OS触发(系统调用),会打断CPU当前运行的指令,跳转到OS(或驱动等)设置的中断服务例程。
信号可以视作OS和进程之间沟通的手段,可以由OS发起,也可以由程序主动发起,由OS管理,OS将信号传递给指定的进程。
C VS C++
C语言没有结构化的异常处理机制,可以约定用返回值来区分正常调用和异常调用,来进行对应的处理。
Perhaps the most common form of exception-handling method used by software programmers is the “return-code” technique that was popularized as part of C and UNIX.
C++提供了结构化的异常处理机制,统一了异常处理的接口,异常可以在调用栈层层传递,也可以更细分的处理不同异常。
抛出异常
语法,关键字raise
:
raise ExceptionClass/ExceptionInstance
如果raise
后跟着异常类,会执行隐式无参初始化。
捕获异常
捕获异常关键字为except
,如果要捕获多个异常,可以显式指定要捕获的多个异常,也可以捕获它们共同的父类。
异常上下文
一个异常可以由另一个异常引起,即异常之间可以由上下文关系。有时候为了统一展示的目的,可能隐藏一些深层的异常,而由外层的异常进行展示。如,将关键字异常转换为属性异常,来隐藏底层是依赖字典实现的。
try:
...
except KeyError as exc:
# raise AttributedError from exc
raise AttributeError from None
此时新异常是一个AttributeError
,其可以由原来的KeyError
触发,也可以由None触发,区别在于:
- from exc:
.__cause__
属性和.__context__
属性均被设置为原来的exc,trace_back会打印新旧异常; - from None:仅
.__context__
属性被隐式设置为原来的异常(便于自省),旧异常被新异常替代,trace_back只会打印新异常;
警告
Warning
是Excetion
的子类。
用途:想要警告用户,同时不终止程序(异常通常会终止),也不强制要求try...except...
子句。
和print
的区别:warnings
模块默认通过sys.stderr
打印警告信息,避免和标准输出混淆。
和logging.warn()
的区别:日志只是忠实地记录警告信息,Warning
重点在于警告用户(通常是开发者)做出修改。
触发警告
使用warnings.warn(msg, category=None, ...)
:
...
>>> warnings.warn('I am a warning!')
./warnings1.py:6: UserWarning: I am a warning!
warnings.warn('I am a warning!')
warnings.warn(...)
的category
参数用来指定警告类型,默认是UserWarning
,其他有DeprecationWarning
、SyntaxWarning
等。
过滤警告
过滤警告就是对警告设置不同的处理方式,warnings
模块提供了过滤器接口,常见的有warnings.simplefilter(action, category=...)
,如:
warnings.simplefilter('error')
warnings.warn('Yikes!')
action参数可以指定不同的处理方式,category参数可以针对不同类型的警告定制处理方式。
action的选项:
- “default” — display a warning the first time it is encountered
- “error” — turn the warning into an exception
- “ignore” — ignore the warning
- “always” — always show the warning, even if it was displayed before
- “module” — show the warning once per module
- “once” — show the warning only once, throughout the program
因为警告是异常的子类,所以可以被正常raise
。
异常的层次
内置异常和警告的层级结构如下:
BaseException
├── BaseExceptionGroup
├── GeneratorExit
├── KeyboardInterrupt
├── SystemExit
└── Exception
├── ArithmeticError
│ ├── FloatingPointError
│ ├── OverflowError
│ └── ZeroDivisionError
├── AssertionError
├── AttributeError
├── BufferError
├── EOFError
├── ExceptionGroup [BaseExceptionGroup]
├── 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
├── StopAsyncIteration
├── StopIteration
├── SyntaxError
│ └── IndentationError
│ └── TabError
├── SystemError
├── TypeError
├── ValueError
│ └── UnicodeError
│ ├── UnicodeDecodeError
│ ├── UnicodeEncodeError
│ └── UnicodeTranslateError
└── Warning
├── BytesWarning
├── DeprecationWarning
├── EncodingWarning
├── FutureWarning
├── ImportWarning
├── PendingDeprecationWarning
├── ResourceWarning
├── RuntimeWarning
├── SyntaxWarning
├── UnicodeWarning
└── UserWarning