转载自:http://blog.csdn.net/gavin_john/article/details/50737689
异常编码细节
这次将学习try、raise、assert和with语句背后的细节。正如我们所看到的,尽管这些语句大多比较简单,但它们提供了强大的工具来处理Python代码中的异常。
=================================================================================
try/except/else语句
try是复合语句,它的最完整的形式如下所示。首先是以try作为首行,后面紧跟着缩进的语句代码,然后是一个或多个except分句来识别要捕捉的异常,最后是一个可选的else分句。try、except和else这些关键字会缩进在相同的层次。
- try:
- <statements>
- except <name1>:
- <statements>
- except <name2,name3>:
- <statemests>
- except <name4> as <data>:
- <statements>
- except:
- <statements>
- else:
- <statements>
=================================================================================
try语句分句
编写try语句时,有一些分句可以在try语句代码块后出现。下表列出了所有可能的形式:
分句形式 | 说明 |
except: | 捕捉所有(其他)异常类型 |
except name: | 只捕捉特定的异常 |
except name,value: | 捕捉所列的异常和其额外的数据(或实例) |
except (name1,name2): | 捕捉任何列出的异常 |
except (name1,name2),value: | 捕捉任何列出的异常,并取得其额外数据 |
else: | 如果没有引发异常,就运行 |
finally: | 总是会运行此代码块,不管有没有发生异常 |
【2】.except子句以括号列出一组异常[except (e1 , e2 , e3):]会捕捉所列出的任何异常。
Python会从头到尾检查except子句,在某个try中寻找是否有相符者,所以括号版本就像是每个异常列在其except子句内,但是语句主体只需要编写一次而已。以下是多个except子句的例子,示范处理器的具体化:
- try:
- action()
- except NameError:
- ...
- except IndexError:
- ...
- except KeyError:
- ...
- except (AttributeError,TypeError,SyntaxError):
- ...
- else:
- ...
如果想要编写通用的“捕捉一切”分句,空的except就可以做到。
- try:
- action()
- except NameError:
- ...
- except IndexError:
- ...
- except:
- ...
- else:
- ...
- try:
- action()
- except:
- ...
- try:
- action()
- except Exception:
- ...
例子:利用try/finally编写终止行为
以下为更加实际的例子,示范了finally子句的典型角色。
- class MyError(Exception):
- pass
- def stuff(file):
- raise MyError()
- file = open('data','w')
- try:
- stuff(file)
- finally:
- file.close()
- print('not reached')
=====================================================================================
统一try/except/finally语句
在Python2.5发布以前的所有Python版本中,try语句都有两种形式,而且都是独立的两种语句:我们可以用finally子句来确保清理代码一定执行,或者编写except代码块来捕捉和恢复特定的异常,还能定义选用的else分句。也就是,finally子句无法与except和else混合。
不过,在Python2.5及其以后的版本中,这两个语句已经合并。现在可以在同一个try语句中混合finally、except以及else子句。也就是,现在可以编写下列形式的语句:
- try:
- main-action
- except Exception1:
- handler1
- except Exception2:
- handler2
- ...
- else:
- else-block
- finally:
- finally-block
try -> except -> else -> finally
其中,else和finally是可选的,可能会有0个或多个except,但是,如果出现一个else的话,必须至少有一个except。
------------------------------------------------------------------------- -------------------------------------------------------------
合并try的例子
下面代码编写了四种常见的场景,通过print语句来说明其意义:
- sep = '-'*32+'\n'
- print(sep+'exception raised and caught')
- try:
- x = 'spam'[99]
- except IndexError:
- print('except run')
- finally:
- print('finally run')
- print('after run')
- print(sep + 'no exception raised')
- try:
- x = 'spam'[3]
- except IndexError:
- print('except run')
- finally:
- print('finally run')
- print('after run')
- print(sep +'no exception raised,with else')
- try:
- x = 'spam'[3]
- except IndexError:
- print('except run')
- else:
- print('else run')
- finally:
- print('finally run')
- print('after run')
- print(sep +'exception raised but not caught')
- try:
- x = 1/0
- except IndexError:
- print('except run')
- finally:
- print('finally run')
- print('after run')
- --------------------------------
- exception raised and caught
- except run
- finally run
- after run
- --------------------------------
- no exception raised
- finally run
- after run
- --------------------------------
- no exception raised,with else
- else run
- finally run
- after run
- --------------------------------
- exception raised but not caught
- finally run
- Traceback (most recent call last):
- File "F:/data/PythonTest/2_25.py", line 47, in <module>
- x = 1/0
- ZeroDivisionError: division by zero
raise语句
要显示的触发异常,可以使用raise语句。raise语句的组成是:raise关键字,后面跟着可选的要引发的类或者类的一个实例:
- raise <instance>
- raise <class>
看一些示例。对于内置异常,如下两种形式是对等的,都会引发指定的异常类的一个实例,但是,第一种形式隐式地创建实例。
- raise IndexError
- raise IndexError()
- exc = IndexError()
- raise exc
- excs = [IndexError,TypeError]
- raise excs[0]
- try:
- ...
- except IndexError as X:
- ...
- >>>
- try:
- raise MyExc('Gavin')
- except MyExc as X:
- print(X.args)
- ('Gavin',)
assert语句
Python还包括了assert语句,它可视为条件式的raise语句。该语句的形式为:
- assert <test>,<data>
- if __debug__:
- if not <test>:
- raise AssertionError(<data>)
assert语句通常用于验证开发期间程序状况的,用来收集用户定义的约束条件,而不是捕捉内在的程序设计错误。应为Python会自行收集程序的设计错误。如下:
- def reciprocal(x):
- assert x != 0
- return 1/x
=====================================================================================
with/as环境管理器
Python3引入了一种新的异常相关的语句:with及其可选的as字句。这个语句的设计是为了和环境管理器对象一起工作。with/as语句的设计师作为常见try/finally用法模式的替代方案。就像try/finally语句,with/as语句也是用于定义必须的终止或“清理行为”,无论处理步骤是否发生异常。
with语句的基本格式如下:
- with expression [as variable]:
- with-block
有些内置的Python对象已经得到强化,支持了环境管理协议,因此可以用于with语句。例如,文件对象有环境管理器,可在with代码块后自动关闭文件,无论是否引发异常。
- with open(r'C:\test\data') as myfile:
- for line in myfile:
- print(line)
- ...
在这个with语句执行后,环境管理机制保证由myfile所引用的文件对象会自动关闭,即使处理该文件时,for循环引发了异常也是如此。然而,我们不能很容易地知道这会何时发生。with语句的这种用法作为一种替代,允许我们确定在一个特定代码块执行完毕后会发生关闭。但我们也可以使用更通用而明确的try/finally语句来实现类似的功能,但是,这需要4行管理代码而不是1行:
- myfile = open(r'C:\test\data')
- try:
- for line in myfile:
- print(line)
- ...
- finally:
- myfile.close()
------------------------------------------------------------------------------ -----------------------------------------------------
环境管理协议这里不做介绍