try/except/else语句
try其实是复合语句,try语句最完整的形式如下:
try:
<statements> #代码主模块
except <name1>: #当产生<name1>异常的时候执行代码块<statements1>
<statements1>
except (<name2>,<name3>): #当产生<name2>,<name3>异常的时候执行代码块<statements2>
<statements2>
except <name4> as <data>: #产生<name4>异常时,将<name4>异常作为实例<data>传入
<statements4>
except: #产生没有包含以上几个异常的其他异常时,执行<statements5>
<statements5>
else: #没有异常发生时,执行statements6
<statements6>
try语句下的代码为程序的主要动作,在except子句下面的语句是各个异常相应的处理器,而else语句(可选)则是提供没有异常发生时要执行的处理器 。这里的”< data >”语句与rasie语句有关,稍后进行说明。
try语句执行代码处理流程如下:
- 先执行try语句下的主要动作代码,如果有异常发生,就会跳出try语句块,并在except子语句中找到第一个符合引发异常的代码块,处理完成后,就会跳过try语句块中的剩下语句,按照顺序执行整个try后的语句。
- 如果发生了异常,但是并没有找到合适的处理该异常的处理器,异常就会被Python程序默认处理(终止程序运行,并打印出相关异常信息)。
- 如果try语句中的主要动作没有发生相关异常,Python就会执行else语句,执行完成后,继续执行后面的Python语句。
总之,except子句是专注于处理异常,当try语句下没有发生异常时,才会去执行else子句下的代码。从语法上讲,except从句没有数量限制,然而一个try语句只能有一个else语句以及一个finally语句。分句的形式总结如下表格:
分句形式 | 说明 |
---|---|
except: | 捕捉所有(其它)异常,一般出现在except分句的最后一个 |
except name: | 捕捉特定异常 |
except name,value: | 捕捉异常和其它额外的数据(或实例) |
except (name1,name2): | 捕捉元组中列出的任何异常 |
except (name1,name2),value: | 捕捉列出的任何异常,并获取额外的数据 |
else: | 如果没有异常发生,就运行该模块 |
finally: | 无论有没有异常发生,总是会运行此模块代码 |
except: 分句形式是一种通用功能可以捕捉一切异常,在Python中即便是系统离开调用,也会触发异常,而你通常会让这些事通过,在Python3.0中可以使用 except Exception:来替代这种通用功能,这与它有相同功能,但是会忽略和系统退出的相关异常。
else语句一般都是放在try代码块中,但是如果知道else分句,会使你的try语句逻辑更加清晰。因为你的代码放在try语句中也有可能发生一些异常。
try/finally语句
try:
<statements1>
finally:
<statements2>
首先执行try语句下的代码,如果没有异常发生,也会执行finally语句。然后再继续执行整个try语句之后的语句。
而如果发生了异常,依然会执行finally代码块。但是接着会把异常信息向上层传递到较高的try语句或顶层默认器,程序不会继续执行try语句后的语句。在Python2.5之后,finally语句可以和try语句的其它分句一起使用,一般都用它来指明一定要执行的“清理”动作(比如服务器断开,文件关闭等),无论异常发生了没有。
finally语句与except分句不一样,finally语句不会拦截异常而是传递异常。如果异常没有在except分句中被拦截,那么就会由默认异常处理器处理(执行完finally分句中的内容后,终止程序运行,并输出异常)
统一try语句语法
try语句必须有一个except或一个finally语法,并且其部分的顺序必须如下:
try -> except -> else -> finally
其中else和finally是可选的,可能会有0个或多个except,但是如果出现一个else的话,必须有至少一个except。总的说来try语句可以有两个部分,一个是带有else(可选的)的except语句,或者带有finally语句
raise语句
raise语句通常用来显式地触发异常,通常有以下几种方法:
raise <instance> # 抛出一个异常实例
raise <class> # 抛出一个异常类(异常状态),其效果相当于在类名后加圆括号。
raise # 最后的形式重新引发最近引发的异常。通常用在异常处理器中,用于传播已补货的异常
异常链:raise from语句
当使用 raise exception from otherexception时,第二个表达式指定了另一个异常类或实例,它会附加到前一个异常的__cause__属性中。
>>> raise TypeError('Bad!') from Exception
Exception
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Bad!
>>>
assert语句
assert语句可以通过条件判断来抛出AssertionError异常。
assert [test],[data]
这个语句执行的效果就像:
if test:
raise AssertioanError([data])
可以使用类似python -0 mani.py 的命令来让python程序中用优化模式运行,并且关闭assert语句。
assert语句通常是用于验证开发期间程序状况的
with语句
基本格式如下:
with expression as [variable]:
<with-block statements>
with语句会用expression返回的支持环境管理协议的对象,赋值给as后面的variable变量。在运行with-block中的语句后终止环境管理协议的对象(比如关闭文件等)。
环境管理协议
要实现一个环境管理器,使得该对象可以接入with语句,该方法属于运算符重载的范畴。
以下是with语句实际的工作方式:
- with表达式所得到得对象为环境管理器,它必须有__enter__和__exit__方法。
- 在with语句开始时,enter方法会被调用,如果存在as子语句,那么返回值会赋值给as子语句后面的变量名,否则直接丢弃
- 嵌套在with语句中代码就会执行
- 如果with内的语句发生了异常,则会将相关参数传到__exit__方法。如果此方法返回值为假,则异常会重新引发。否则异常会终止。正常情况下,异常时应该被重新引发,这样的话才能传递到with语句之外。
- 如果with内的语句没有异常发生,__exit__方法依然会被调用,但是参数都是以None传递。
>>> class TraceBlock:
... def message(self,arg):
... print('running', arg)
... def __enter__(self):
... print("starting enter block")
... return self
... def __exit__(self,exc_type,exc_value,exc_tb):
... print("starting exit block")
... print(exc_type,exc_value,exc_tb)
... if exc_type is None:
... print('exited normally')
... else:
... print("raise an exception", exc_type)
... return False
...
>>> with TraceBlock() as lxm:
... lxm.message("testtest")
...
starting enter block
running testtest
starting exit block
None None None
exited normally
>>>
>>> with TraceBlock() as lxm:
... lxm.message("testtest")
... raise TypeError
...
starting enter block
running testtest
starting exit block
<class 'TypeError'> <traceback object at 0x7ff163181c48>
raise an exception <class 'TypeError'>
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
TypeError
>>>
以上例子可以看出,环境管理器会以__enter__和__exit__跟踪with语句代码块的进入和离开。
在python3.1的版本中,可以在一个with语句中直接使用两个环境管理器:
with open("data") as fin, open("res",'w') as fout:
<statements>
当with语句运行完成后,这两个环境管理器都会退出。
小结
异常管理编码有几个语句,try是标识需要捕捉异常的主程序,except是捕捉各类异常,raise是触发异常,assert是条件式引发异常,而with是把代码块包装在环境管理器中(定义了__enter__和__exit__方法。)