1. 程式人生 > >Python異常捕捉try except else finally有return時執行順序探究

Python異常捕捉try except else finally有return時執行順序探究

復制代碼 捕獲 key clas 沖突 light 問題 進入 odi

轉載自 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
技術分享圖片 上面的代碼是一直要使用的代碼,只不過暫時不用的代碼被comment了。

有異常發生,並且捕獲異常,最後在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

Python異常捕捉try except else finally有return時執行順序探究