python try except else finally 执行顺序详细分析

来源:互联网 发布:西安电子科技大学网络教育 编辑:程序博客网 时间:2024/05/24 06:44
 

python try except else finally 执行顺序详细分析

分类: Python 193人阅读 评论(0) 收藏 举报

学习python或者其他有异常控制的编程语言, 大家很有可能说try except finally(try catch finally)的执行很简单,无非就是有异常的话执行except, finally无论是否有异常都会执行, 大致上原则是这样, 但是如果涉及到更加详细的复杂的路径,加上return 语句,就没有那么简单了。


1. 没有return 语句的情况


[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. print 'this is a test of code path in try...except...else...finally'  
  2. print '************************************************************'  
  3.   
  4. def exceptTest():  
  5.     try:  
  6.         print 'doing some work, and maybe exception will be raised'  
  7.         raise IndexError('index error')  
  8.         #print 'after exception raise'  
  9.         #return 0  
  10.           
  11.     except KeyError, e:  
  12.         print 'in KeyError except'  
  13.         print e  
  14.         #return 1  
  15.     except IndexError, e:  
  16.         print 'in IndexError except'  
  17.         print e  
  18.         #return 2  
  19.     except ZeroDivisionError, e:  
  20.         print 'in ZeroDivisionError'  
  21.         print e  
  22.         #return 3  
  23.     else:  
  24.         print 'no exception'  
  25.         #return 4  
  26.     finally:  
  27.         print 'in finally'  
  28.         #return 5  
  29.   
  30. resultCode = exceptTest()  
  31. print resultCode  

上面的代码是一直要使用的代码,只不过暂时不用的代码被comment了。

有异常发生,并且捕获异常,最后在finally进行处理,上面代码的输出:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. this is a test of code path in try...except...else...finally  
  2. ************************************************************  
  3. doing some work, and maybe exception will be raised  
  4. in IndexError except  
  5. index error  
  6. in finally  
  7. None  

然后我们逐渐给上面代码各个情况添加return 语句, 查看添加return 语句后的代码执行效果。


2. 添加return 语句的情况


[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. print 'this is a test of code path in try...except...else...finally'  
  2. print '************************************************************'  
  3.   
  4. def exceptTest():  
  5.     try:  
  6.         print 'doing some work, and maybe exception will be raised'  
  7.         raise IndexError('index error')  
  8.         print 'after exception raise'  
  9.         return 0  
  10.           
  11.     except KeyError, e:  
  12.         print 'in KeyError except'  
  13.         print e  
  14.         return 1  
  15.     except IndexError, e:  
  16.         print 'in IndexError except'  
  17.         print e  
  18.         return 2  
  19.     except ZeroDivisionError, e:  
  20.         print 'in ZeroDivisionError'  
  21.         print e  
  22.         return 3  
  23.     else:  
  24.         print 'no exception'  
  25.         return 4  
  26.     finally:  
  27.         print 'in finally'  
  28.         return 5  
  29.   
  30. resultCode = exceptTest()  
  31. print resultCode  

这个时候所有的分支都存在return 语句,并且会引发异常, 看一下输出:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. this is a test of code path in try...except...else...finally  
  2. ************************************************************  
  3. doing some work, and maybe exception will be raised  
  4. in IndexError except  
  5. index error  
  6. in finally  
  7. 5  

异常发生后,raise语句以后的不再执行,然后到了捕获异常语句, 但是捕获异常模块有个return , 是不是这个时候就不再继续执行直接返回呢?但是这是跟  finally语句必然执行是相冲突的, 可以在结果中看到finally实际上执行了,并且返回值是5,在 finally de 的返回值。


然后,我们在看看把finally 的返回值注释掉,看看返回值是多少?

代码如下:

[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. print 'this is a test of code path in try...except...else...finally'  
  2. print '************************************************************'  
  3.   
  4. def exceptTest():  
  5.     try:  
  6.         print 'doing some work, and maybe exception will be raised'  
  7.         raise IndexError('index error')  
  8.         print 'after exception raise'  
  9.         return 0  
  10.           
  11.     except KeyError, e:  
  12.         print 'in KeyError except'  
  13.         print e  
  14.         return 1  
  15.     except IndexError, e:  
  16.         print 'in IndexError except'  
  17.         print e  
  18.         return 2  
  19.     except ZeroDivisionError, e:  
  20.         print 'in ZeroDivisionError'  
  21.         print e  
  22.         return 3  
  23.     else:  
  24.         print 'no exception'  
  25.         return 4  
  26.     finally:  
  27.         print 'in finally'  
  28.         #return 5  
  29.   
  30. resultCode = exceptTest()  
  31. print resultCode  

这个时候的程序输出:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. this is a test of code path in try...except...else...finally  
  2. ************************************************************  
  3. doing some work, and maybe exception will be raised  
  4. in IndexError except  
  5. index error  
  6. in finally  
  7. 2  

返回值变为2, 这个时候有点疑惑了, 先不用解释问题,我们继续看其他的情况。


3. 没有异常发生且try语句块没有return

代码如下:

[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. print 'this is a test of code path in try...except...else...finally'  
  2. print '************************************************************'  
  3.   
  4. def exceptTest():  
  5.     try:  
  6.         print 'doing some work, and maybe exception will be raised'  
  7.         #raise IndexError('index error')  
  8.         print 'after exception raise'  
  9.         #return 0  
  10.           
  11.     except KeyError, e:  
  12.         print 'in KeyError except'  
  13.         print e  
  14.         return 1  
  15.     except IndexError, e:  
  16.         print 'in IndexError except'  
  17.         print e  
  18.         return 2  
  19.     except ZeroDivisionError, e:  
  20.         print 'in ZeroDivisionError'  
  21.         print e  
  22.         return 3  
  23.     else:  
  24.         print 'no exception'  
  25.         return 4  
  26.     finally:  
  27.         print 'in finally'  
  28.         return 5  
  29.   
  30. resultCode = exceptTest()  
  31. print resultCode  

这个时候的代码输出:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. this is a test of code path in try...except...else...finally  
  2. ************************************************************  
  3. doing some work, and maybe exception will be raised  
  4. after exception raise  
  5. no exception  
  6. in finally  
  7. 5  

这里验证了如果没有异常那么else语句是执行的,并且finally语句执行,然后返回finally语句的return 5


但是,当try语句块里存在return语句是什么情况呢?

4. 没有异常发生且try语句块 存在return语句

[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. print 'this is a test of code path in try...except...else...finally'  
  2. print '************************************************************'  
  3.   
  4. def exceptTest():  
  5.     try:  
  6.         print 'doing some work, and maybe exception will be raised'  
  7.         #raise IndexError('index error')  
  8.         print 'after exception raise'  
  9.         return 0  
  10.           
  11.     except KeyError, e:  
  12.         print 'in KeyError except'  
  13.         print e  
  14.         return 1  
  15.     except IndexError, e:  
  16.         print 'in IndexError except'  
  17.         print e  
  18.         return 2  
  19.     except ZeroDivisionError, e:  
  20.         print 'in ZeroDivisionError'  
  21.         print e  
  22.         return 3  
  23.     else:  
  24.         print 'no exception'  
  25.         return 4  
  26.     finally:  
  27.         print 'in finally'  
  28.         return 5  
  29.   
  30. resultCode = exceptTest()  
  31. print resultCode  

执行结果:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. this is a test of code path in try...except...else...finally  
  2. ************************************************************  
  3. doing some work, and maybe exception will be raised  
  4. after exception raise  
  5. in finally  
  6. 5  

这里else没有执行,和我们对于书本知识有冲突了, finally语句执行并返回5.

分析: 这里因为没有发生异常, 所以会执行到try块中的return 语句,但是finally又必须执行,所以执行try中return 之前去执行了finally语句,并且可以认为,finally语句修改了最后返回的值,将try中的返回值修改为5并最终返回,所以else语句并没有得到执行。


5. 有异常发生并且finally 没有return 语句


[python] view plaincopy在CODE上查看代码片派生到我的代码片
  1. print 'this is a test of code path in try...except...else...finally'  
  2. print '************************************************************'  
  3.   
  4. def exceptTest():  
  5.     try:  
  6.         print 'doing some work, and maybe exception will be raised'  
  7.         raise IndexError('index error')  
  8.         print 'after exception raise'  
  9.         return 0  
  10.           
  11.     except KeyError, e:  
  12.         print 'in KeyError except'  
  13.         print e  
  14.         return 1  
  15.     except IndexError, e:  
  16.         print 'in IndexError except'  
  17.         print e  
  18.         return 2  
  19.     except ZeroDivisionError, e:  
  20.         print 'in ZeroDivisionError'  
  21.         print e  
  22.         return 3  
  23.     else:  
  24.         print 'no exception'  
  25.         return 4  
  26.     finally:  
  27.         print 'in finally'  
  28.         #return 5  
  29.   
  30. resultCode = exceptTest()  
  31. print resultCode  

执行结果:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. this is a test of code path in try...except...else...finally  
  2. ************************************************************  
  3. doing some work, and maybe exception will be raised  
  4. in IndexError except  
  5. index error  
  6. in finally  
  7. 2  

因为有异常发生,所以try中的return语句肯定是执行不到的,然后在捕获到的except中进行执行,并且except中存在return 语句,那么是不是就直接返回? 因为finally 语句是必须要执行的,所以这里的return语句需要先暂且放下,进入finally进行执行,然后finnaly执行完以后再返回到 except中进行执行。


看到这里,我们貌似找到了一些规律

1. 如果没有异常发生, try中有return 语句, 这个时候else块中的代码是没有办法执行到的, 但是finally语句中如果有return 语句会修改最终的返回值, 我个人理解的是try中return 语句先将要返回的值放在某个 CPU寄存器,然后运行finally语句的时候修改了这个寄存器的值,最后在返回到try中的return语句返回修改后的值。

2. 如果没有异常发生, try中没有return语句,那么else块的代码是执行的,但是如果else中有return, 那么也要先执行finally的代码, 返回值的修改与上面一条一致。

3. 如果有异常发生,try中的return语句肯定是执行不到, 在捕获异常的 except语句中,如果存在return语句,那么也要先执行finally的代码,finally里面的代码会修改最终的返回值,然后在从except 块的retrun 语句返回最终修改的返回值, 和第一条一致。

0 0