# [Python] 例外執行順序
###### tags: `python`
:::info
* break、return、raise都會使程序跳出try/except/finally對應的區塊
* finally的區塊總是在整個try/except之後執行
* return的結果可以被覆蓋
* 函數的返回值在finally之後才"返回"
* Exception是BaseException的子類別,可以捕捉除了系統例外以外的所有例外,也就可以藉由KeyboardInterrupt中斷迴圈。
:::
try finally break return raise
```python=
def test():
try:
int("TEST")
return "try"
except Exception as error:
print("Before raise")
return "except"
raise ValueError from error
print("After raise")
finally:
print("Finally")
return "finally"
print("return: ", test())
===output===
Before raise
Finally
return: finally
```
finally即使是在return的情況下依然會執行,甚至可以覆蓋return的結果!
```python=
def test():
try:
int("TEST")
return "try"
except Exception as error:
print("Before raise")
raise ValueError from error
print("After raise")
return "except"
finally:
print("Finally")
return "finally"
print("return: ", test())
===output===
Before raise
Finally
return: finally
```
不管使用raise或return都會立即跳出該區塊! 而raise拋出的順序會在finally執行之後,但是遇到return就不執行。
```
註解 # return "finally"
===output===
Before raise
Finally
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-21-34cfccebe447> in test()
2 try:
----> 3 int("TEST")
4 return "try"
ValueError: invalid literal for int() with base 10: 'TEST'
The above exception was the direct cause of the following exception:
ValueError Traceback (most recent call last)
<ipython-input-21-34cfccebe447> in <module>()
12 # return "finally"
13
---> 14 print("return: ", test())
<ipython-input-21-34cfccebe447> in test()
5 except Exception as error:
6 print("Before raise")
----> 7 raise ValueError from error
8 print("After raise")
9 return "except"
ValueError:
```
```python=
i = 0
while True:
try:
if i == 0:
print("break")
break
except Exception:
print("except")
finally:
print("finally")
===output===
break
finally
```
```python=
def test_return(i):
while True:
try:
if i == 0:
print("return")
return i
except Exception:
print("except")
finally:
print("finally")
print("return: ", test_return(0))
===output===
return
finally
return: 0
```
```python=
import sys
try:
raise EOFError
except:
type_, message, traceback = sys.exc_info()
print(type_)
print(message)
print(traceback)
===output===
<class 'EOFError'>
<traceback object at 0x000001E526C17048>
```
```python=
try:
try:
raise EOFError('EOFError')
except EOFError as e:
print(e.args)
raise IndexError('IndexError') from e
except IndexError as e:
print(e.args)
print(e.__cause__.args)
print(e.__context__.args)
===output===
('EOFError',)
('IndexError',)
('EOFError',)
('EOFError',)
```
raise from語法,會將from後接上的例外實例,設定給被raise的例外實例之__cause__。
實際上,如果你在except中raise某個例外,則原except所比對到的例外,無論有無使用raise from,都會自動設定給__context__。
## 參考
[實作執行情況(1)](https://www.jianshu.com/p/343fe0942b80)
[實作執行情況(2)](https://openhome.cc/Gossip/Python/TryRaise.html)