預覽
try語句按照如下方式工作;
- 首先,執行try子句(在關鍵字try和關鍵字except之間的語句)
- 如果沒有異常發生,忽略except子句,try子句執行後結束。
- 如果在執行try子句的過程中發生了異常,那麼try子句餘下的部分将被忽略。如果異常的類型和 except 之後的名稱相符,那麼對應的except子句将被執行。最後執行 try 語句之後的代碼。
- 如果一個異常沒有與任何的except比對,那麼這個異常将會傳遞給上層的try中。
一個 try 語句可能包含多個except子句,分别來處理不同的特定的異常。最多隻有一個分支會被執行。
處理程式将隻針對對應的try子句中的異常進行處理,而不是其他的 try 的處理程式中的異常。
一個except子句可以同時處理多個異常,這些異常将被放在一個括号裡成為一個元組,
Python 中(至少)有兩種錯誤:文法錯誤和異常(syntax errors 和 exceptions)
文法錯誤,也被稱作解析錯誤
while True print('Hello world')
File "<ipython-input-2-614901b0e5ee>", line 1
while True print('Hello world')
^
SyntaxError: invalid syntax
文法分析器指出錯誤行,并且在檢測到錯誤的位置前面顯示一個小“箭頭”。 錯誤是由箭頭前面的标記引起的(或者至少是這麼檢測的)
5/0
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-1-67a69f72677d> in <module>()
----> 1 5/0
ZeroDivisionError: division by zero
try:
print(5/0)
except ZeroDivisionError:
print("You can't divide zero!")
You can't divide zero!
print("Give me two numbers,and I'll divide them.")
print("Enter'q' to quit.")
while True:
first_number = input('\nFist number: ')
if first_number == 'q':
break
second_number = input('\nsecond number: ')
if second_number == 'q':
break
answer = int(first_number) / int(second_number)
print(answer)
Give me two numbers,and I'll divide them.
Enter'q' to quit.
Fist number: 5
second number: 0
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-4-c303f6ef9aca> in <module>()
9 if second_number == 'q':
10 break
---> 11 answer = int(first_number) / int(second_number)
12 print(answer)
ZeroDivisionError: division by zero
# 異常
print("Give me two numbers,and I'll divide them.")
print("Enter'q' to quit.")
while True:
first_number = input('\nFist number: ')
if first_number == 'q':
break
second_number = input('\nsecond number: ')
if second_number == 'q':
break
try:
answer = int(first_number) / int(second_number)
except ZeroDivisionError:
print("You can't divide zero!")
else:
print(answer)
Give me two numbers,and I'll divide them.
Enter'q' to quit.
Fist number: 5
second number: 0
You can't divide zero!
Fist number: 5
second number: 3
1.6666666666666667
Fist number: q
異常
異常:即程式運作時遇到非正常的情況,如符号錯誤,邏輯錯誤,文法錯誤等等。
python語言使用異常對象(exception object)來表示異常情況,由于它是一種面向對象語言,是以程式中抛出的異常也是一種類,所有的異常都是從基類Exception繼承而來,而且是在Exceptions子產品中被定義。Python将所有異常名稱放在内建的命名空間中,使用者在使用異常時不需要導入任何子產品。若異常出現時程式沒有進行捕捉或處理,在程式中會使用回溯(Traceback)來終止執行。
異常有兩種激活方式:
- 在程式運作出錯時自動引發
- 程式員自己引發,即抛出異常
抛出異常
抛出異常往往是程式自動根據錯誤特征進行自動識别和抛出,在python中可以使用raise語句強制抛出異常。
raise語句
當程式員想要抛出一個異常時,直接在raise語句中指明錯誤或異常的名稱即可。
用法:
raise [SomeException [,arg[,traceback]]
- SomeException是引發異常的名字,它必須是一個異常類,或異常類的執行個體;
- args(可選參數)傳遞給SomeException的參數,可以是元組或者是一個單獨的對象。(因為異常參數隻能為元組,是以當args是一個單獨的對象,傳入時會生成一個隻有一個元素的元組)
- traceback(可選參數),它是當異常觸發時新生産成一個用于異常-正常化的跟蹤記錄對象。
raise Exception
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
<ipython-input-5-fca2ab0ca76b> in <module>()
----> 1 raise Exception
Exception:
raise NameError # 觸發類異常
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-10-0350581f77f1> in <module>()
----> 1 raise NameError # 觸發類異常
NameError:
raise NameError() # 觸發類的執行個體異常
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-9-1ca845d32a12> in <module>()
----> 1 raise NameError() # 觸發類的執行個體異常
NameError:
raise NameError("This is NameError Exception")
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-16-7324116b3e3f> in <module>()
----> 1 raise NameError("This is NameError Exception")
NameError: This is NameError Exception
raise Exception(NameError("This is NameError Exception"))
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
<ipython-input-18-da4ad2b05f15> in <module>()
----> 1 raise Exception(NameError("This is NameError Exception"))
Exception: This is NameError Exception
自定義異常類
- 1)繼承Exception類
- 2)使用raise語句通過人工的方式觸發
示例:
class CustomError(Exception):
pass
# raise觸發
raise CustomError
---------------------------------------------------------------------------
CustomError Traceback (most recent call last)
<ipython-input-19-324753841193> in <module>()
3
4 # raise觸發
----> 5 raise CustomError
CustomError:
class MyError(Exception):
def __init__(self,value):
super(MyError,self).__init__(value)
self.value=value
raise MyError("Error Information")
---------------------------------------------------------------------------
MyError Traceback (most recent call last)
<ipython-input-21-e7eca55e3136> in <module>()
5
6
----> 7 raise MyError("Error Information")
MyError: Error Information
捕獲異常
目的:使程式能夠不崩潰且正确運作
try-except 語句
- 将可能出現異常的語句放到try子句;
- 将處理異常的語句放到except子句中。
try:
tryblock
except Exception:
exception block
工作方式:
- 首先執行try子句。若沒有發生任何異常,except子句會在try子句執行完後被忽略。
- 若try子句引發異常,則try子句引發的這個異常的代碼會被忽略掉。
- 若引發的異常與except中指定的異常的類型相比對,則會跳到except子句中執行except子句;
- 若引發的異常在except子句中沒有與之相比對的分支,它會傳遞到上一級的try子句中;
- 若仍然找不到與之比對的except子句,它就會成為一個未處理異常,此時程式會終止運作,并且提示異常資訊。
- except子句可以沒有接任何異常和異常參數,這時try語句捕獲的任何異常都會交給except子句來處理。
try:
1/0
except ZeroDivisionError:
print('The divisor cannot be zero')
The divisor cannot be zero
def this_fails():
x = 1/0
try:
this_fails()
except ZeroDivisionError as err:
print('Handling run-time error:', err)
Handling run-time error: division by zero
try-except-else 結構
- 若try範圍内捕獲了except語句指定的異常,就跳到except語句中繼續執行;
- 若try範圍内沒有捕獲任何異常,就執行else語句。
try:
myfile=open('myfile.txt','w')
except:
print('myfile open failed')
else:
print('myfile open successfully')
myfile.close()
myfile open successfully
class Error(Exception):
"""Base class for exceptions in this module."""
pass
class InputError(Error):
"""Exception raised for errors in the input.
Attributes:
expression -- input expression in which the error occurred
message -- explanation of the error
"""
def __init__(self, expression, message):
self.expression = expression
self.message = message
class TransitionError(Error):
"""Raised when an operation attempts a state transition that's not
allowed.
Attributes:
previous -- state at beginning of transition
next -- attempted new state
message -- explanation of why the specific transition is not allowed
"""
def __init__(self, previous, next, message):
self.previous = previous
self.next = next
self.message = message
finally語句
finally語句是指無論是否引發異常,是否被捕獲都一定會執行的代碼塊。
try-finally語句
這種組合其實無法捕捉異常
- 若沒有發生異常,則先運作try子句,然後運作finally子句;
- 若發生異常,則執行finally子句,然後把異常遞交給上層try,控制流不會通過整個try語句。
類似的還有:
try-except-finally語句
## try-except-else-finally語句
finally語句的特性:
- 當在try語句中含有return語句時,執行到return并不會直接傳回,而時在執行finally語句後再執行return語句;
- 有時在處理玩finally中的資源釋放之後就不需要繼續處理抛出的異常了,這這種情況下可以考慮在finally語句塊中使用return語句。
處理異常的特殊方法
assert語句
若斷言成功則不采取任何措施,否則會觸發AssertionError的異常。
assert 1==2,'one does not equal two!'
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-39-3ffa52fc9c11> in <module>()
----> 1 assert 1==2,'one does not equal two!'
AssertionError: one does not equal two!
with語句(上下文管理語句)
with語句的目的在于從流程圖中把try,except和finally關鍵字和資源配置設定釋放相關代碼統統去掉,而不像try-except-finally那樣僅僅簡化代碼使之易用。
- 基本用法:
with context_expr[as var]:
withblock
- 操作檔案對象:
with open(r'somefileName') as somefile:
for line in somefile:
print(line)
...
使用with語句,不管在處理檔案過程是否發生異常,都能保證with語句執行完後已經關閉了打開的檔案句柄。
with語句是一個控制流語句,它引用了一個上下文管理協定,實作方法是為一個類定義
__enter__
和
__exit__
兩個函數。每次使用with語句,會首先執行
__enter__
函數,它的傳回值指派給var,當withblock執行完後,會執行
__exit__
函數。
with語句等價與于
try:
執行__enter__函數
執行withblock
finally:
執行__exit__
探尋有趣之事!