# 异常
1.Python中,异常会根据错误自动地被触发,也能由代码主动触发和截获
2.捕捉异常的代码:
```
try:
statements #该代码执行主要的工作,并有可能引起异常
except ExceptionType1: #except子句定义异常处理,这里捕捉特定的ExceptionType1类型的异常
statements
except (ExceptionType2,ExceptionType3): #except子句定义异常处理,
#这里捕捉任何列出的异常(即只要是ExceptionType2类型或者ExceptionType3类型)
statements
except ExceptionType4 as excp: #这里捕捉特定的ExceptionType4类型异常,但是用变量名excp引用异常对象
statements #这里可以使用excp引用捕捉的异常对象
except: # 该子句捕获所有异常
statements
else: #如果没有发生异常,这来到这里;当发生了异常则不执行else子句
statements
```
* 当`try`子句执行时发生异常,则Python会执行第一个匹配该异常的`except`子句。当`except`子句执行完毕之后(除非该`except`子句 又引发了另一个异常),程序会跳转到整体语句之后执行。
>整体语句就是指上面的`try..except..else`
* 如果异常发生在`try`代码块内,且无匹配的`except`子句,则异常向上传递到本`try`块外层的`try`块中。如果已经传递到了顶层了异常还没有被捕捉,则Python会终止程序并且打印默认的出错消息
* 如果`try`代码块内语句未产生异常,则Python会执行`else`子句,然后程序会在整体语句之后继续执行

3.`try/finally`语句:
```
try:
statements
finally:
statements
```
无论`try`代码块执行时是否发生了异常,`finally`子句一定会被执行
* 若`try`子句无异常,则Python会接着执行`finally`子句,执行完之后程序会跳转到整体语句之后执行
* 若`try`子句有异常,则Python会跳转到`finally`子句中,并接着把异常向上传递

4.Python中的`try|except|finally`统一格式:
```
try:
statements #该代码执行主要的工作,并有可能引起异常
except ExceptionType1: #except子句定义异常处理,这里捕捉特定的ExceptionType1类型的异常
statements
except (ExceptionType2,ExceptionType3): #except子句定义异常处理,
#这里捕捉任何列出的异常(即只要是ExceptionType2类型或者ExceptionType3类型)
statements
except ExceptionType4 as excp: #这里捕捉特定的ExceptionType4类型异常,但是用变量名excp引用异常对象
statements #这里可以使用excp引用捕捉的异常对象
except: # 该子句捕获所有异常
statements
else: # 如果没有发生异常,这来到这里;当发生了异常则不执行else子句
statements
finally: # 一定会执行这个子句
statements
```
* `else`、`finally`子句可选;`except`子句可能有0个或者多个。但是如果有`else`子句,则至少有一个`except`
* `finally`执行时机:无论有没有异常抛出,在程序跳出整体语句之前的最后时刻一定会执行
>整体语句就是指上面的`try..except..else...finally`

5.要显式触发异常,可以用`raise`语句。有三种形式的形式:
* `raise exception_obj`:抛出一个异常实例
* `raise Exception_type`:抛出一个指定异常类型的实例,调用`Exception_type()`获得
* `raise from `:
第二个异常实例会附加到第一个异常实例的`.__cause__`属性中并抛出第一个异常实例
* `raise`:转发当前作用域中激活的异常实例。若当前作用域中没有激活的异常实例,则抛出`RuntimeError`实例对象
* 一旦异常在程序中由某个`except`子句捕获,则它就死掉了不会再传递
* `raise`抛出的必须是一个`BaseException`实例或者`BaseException`子类,否则抛出`TypeError`
>`BaseException`类是所有内建异常的父类。
>
>`Exception`类是所有内建异常、`non-system-exiting`异常的父类。用于自定义的异常类也应该从该类派生


6.在一个异常处理器内部`raise`一个异常时,前一个异常会附加到新异常的`__context__`属性
* 如果在异常处理器内部`raise`被捕获的异常自己,则并不会添加到`__context__`属性

* 在异常处理器内部`raise`与`raise e`效果相同

7.`assert`语句可能会引起`AssertionError`。其用法为:`assert ,`。这等价于:
```
if __debug__:
if not :
raise AssertionError()
```
* ``表达式用于计算真假,``表达式用于作为异常的参数。若``计算为假,则抛出`AssertionError`
* 若执行时用命令行 `-0`标志位,则关闭`assert`功能(默认是打开的)。
> `__debug__`是内置变量名。当有`-0`标志位时,它为0;否则为1
* 通常`assert`用于给定约束条件,而不是用于捕捉程序的错误。

8.Python3中有一种新的异常相关语句:`with/as`语句。它是作为`try/finally`的替代方案。用法为:
```
with expression [as var]:
statements
```
`expression`必须返回一个对象,该对象必须支持环境管理协议。其工作方式为:
* 计算`expression`表达式的值,得到环境管理器对象。环境管理器对象必须有`.__enter__(self)`方法和`.__exit__(self, exc_type, exc_value, traceback)`方法
* 调用环境管理器对象的`.__enter__(self)`方法。如果有`as`子句,`.__enter__(self)`方法返回值赋值给`as`子句中的变量`var`;如果没有`as`子句,则`.__enter__(self)`方法返回值直接丢弃。**并不是将环境管理器对象赋值给`var`**
* 执行`statements`代码块
* 如果`statements`代码块抛出异常,则`.__exit__(self, exc_type, exc_value, traceback)`方法自动被调用
>在内部这几个实参由`sys.exc_info()`返回`(exc_type, exc_value, traceback)`信息,
* 若`.__exit__()`方法返回值为`False`,则重新抛出异常到`with`语句之外
* 若`.__exit__()`方法返回值为`True`,则异常终止于此,并不会抛出`with`语句之外
* 如果`statements`代码块未抛出异常,则`.__exit__(self, exc_type, exc_value, traceback)`方法自动被调用,调用参数为:`.__exit__(self,None,None,None)`

9.Python3.1之后,`with`语句可以指定多个环境管理器,以逗号分隔。根据定义的顺序这些环境管理器对象的`.__enter__(self)`方法顺序调用,`.__exit__(self, exc_type, exc_value, traceback)`方法逆序调用
>如果对象要支持环境管理协议,则必须实现`.__enter__(self)`方法和`.__exit__(self, exc_type, exc_value, traceback)`方法
