轉載自 https://www.cnblogs.com/JohnABC/p/4065437.html
學習python或者其他有異常控制的編程語 言, 大家很有可能說try except finally(try catch finally)的執行很簡單,無非就是有異常的話執行except, finally無論是否有異常都會執行, 大致上原則是這樣, 但是如果涉及到更加詳細的復雜的路徑,加上return 語句,就沒有那么簡單了。
1. 沒有return 語句的情況
print 'this is a test of code path in try...except...else...finally' print '************************************************************' def exceptTest(): try: print 'doing some work, and maybe exception will be raised' raise IndexError('index error') #print 'after exception raise' #return 0 except KeyError, e: print 'in KeyError except' print e #return 1 except IndexError, e: print 'in IndexError except' print e #return 2 except ZeroDivisionError, e: print 'in ZeroDivisionError' print e #return 3 else: print 'no exception' #return 4 finally: print 'in finally' #return 5 resultCode = exceptTest() print resultCode
有異常發生,並且捕獲異常,最后在finally進行處理,上面代碼的輸出:
this is a test of code path in try...except...else...finally ************************************************************ doing some work, and maybe exception will be raised in IndexError except index error in finally None
然后我們逐漸給上面代碼各個情況添加return 語句, 查看添加return 語句后的代碼執行效果。
2. 添加return 語句的情況
print 'this is a test of code path in try...except...else...finally' print '************************************************************' def exceptTest(): try: print 'doing some work, and maybe exception will be raised' raise IndexError('index error') print 'after exception raise' return 0 except KeyError, e: print 'in KeyError except' print e return 1 except IndexError, e: print 'in IndexError except' print e return 2 except ZeroDivisionError, e: print 'in ZeroDivisionError' print e return 3 else: print 'no exception' return 4 finally: print 'in finally' return 5 resultCode = exceptTest() print resultCode
這個時候所有的分支都存在return 語句,並且會引發異常, 看一下輸出:
this is a test of code path in try...except...else...finally ************************************************************ doing some work, and maybe exception will be raised in IndexError except index error in finally 5
異常發生后,raise語句以后的不再執行,然后到了捕獲異常語句, 但是捕獲異常模塊有個return , 是不是這個時候就不再繼續執行直接返回呢?但是這是跟 finally語句必然執行是相沖突的, 可以在結果中看到finally實際上執行了,並且返回值是5,在 finally de 的返回值。
然后,我們在看看把finally 的返回值注釋掉,看看返回值是多少?
代碼如下:
print 'this is a test of code path in try...except...else...finally' print '************************************************************' def exceptTest(): try: print 'doing some work, and maybe exception will be raised' raise IndexError('index error') print 'after exception raise' return 0 except KeyError, e: print 'in KeyError except' print e return 1 except IndexError, e: print 'in IndexError except' print e return 2 except ZeroDivisionError, e: print 'in ZeroDivisionError' print e return 3 else: print 'no exception' return 4 finally: print 'in finally' #return 5 resultCode = exceptTest() print resultCode
這個時候的程序輸出:
this is a test of code path in try...except...else...finally ************************************************************ doing some work, and maybe exception will be raised in IndexError except index error in finally 2
返回值變為2, 這個時候有點疑惑了, 先不用解釋問題,我們繼續看其他的情況。
3. 沒有異常發生且try語句塊沒有return
代碼如下:
print 'this is a test of code path in try...except...else...finally' print '************************************************************' def exceptTest(): try: print 'doing some work, and maybe exception will be raised' #raise IndexError('index error') print 'after exception raise' #return 0 except KeyError, e: print 'in KeyError except' print e return 1 except IndexError, e: print 'in IndexError except' print e return 2 except ZeroDivisionError, e: print 'in ZeroDivisionError' print e return 3 else: print 'no exception' return 4 finally: print 'in finally' return 5 resultCode = exceptTest() print resultCode
這個時候的代碼輸出:
this is a test of code path in try...except...else...finally ************************************************************ doing some work, and maybe exception will be raised after exception raise no exception in finally 5
這里驗證了如果沒有異常那么else語句是執行的,並且finally語句執行,然后返回finally語句的return 5
但是,當try語句塊里存在return語句是什么情況呢?
4. 沒有異常發生且try語句塊 存在return語句
print 'this is a test of code path in try...except...else...finally' print '************************************************************' def exceptTest(): try: print 'doing some work, and maybe exception will be raised' #raise IndexError('index error') print 'after exception raise' return 0 except KeyError, e: print 'in KeyError except' print e return 1 except IndexError, e: print 'in IndexError except' print e return 2 except ZeroDivisionError, e: print 'in ZeroDivisionError' print e return 3 else: print 'no exception' return 4 finally: print 'in finally' return 5 resultCode = exceptTest() print resultCode
執行結果:
this is a test of code path in try...except...else...finally ************************************************************ doing some work, and maybe exception will be raised after exception raise in finally 5
這里else沒有執行,和我們對於書本知識有沖突了, finally語句執行並返回5.
分析: 這里因為沒有發生異常, 所以會執行到try塊中的return 語句,但是finally又必須執行,所以執行try中return 之前去執行了finally語句,並且可以認為,finally語句修改了最后返回的值,將try中的返回值修改為5並最終返回,所以else語句並沒有 得到執行。
5. 有異常發生並且finally 沒有return 語句
print 'this is a test of code path in try...except...else...finally' print '************************************************************' def exceptTest(): try: print 'doing some work, and maybe exception will be raised' raise IndexError('index error') print 'after exception raise' return 0 except KeyError, e: print 'in KeyError except' print e return 1 except IndexError, e: print 'in IndexError except' print e return 2 except ZeroDivisionError, e: print 'in ZeroDivisionError' print e return 3 else: print 'no exception' return 4 finally: print 'in finally' #return 5 resultCode = exceptTest() print resultCode
執行結果:
this is a test of code path in try...except...else...finally ************************************************************ doing some work, and maybe exception will be raised in IndexError except index error in finally 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 語句返回最終修改的返回值, 和第一條一致。
轉自:http://www.2cto.com/kf/201405/304975.html