【Python学习】python学习手册--第三十三章 异常编码细节

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__方法。)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章