全網最適合入門的物件導向程式設計教程:24 類和物件的 Python 實現-異常的捕獲與處理:try/except 語句、檔案讀寫示例、Exception 引用
摘要:
本文主要介紹了在使用 Python 物件導向程式設計時,如何使用 try/except 語句捕獲並處理異常,並輔以 CSV 檔案讀寫為例進行講解,同時說明了如何對 Exception 物件進行引用。
原文連結:
FreakStudio的部落格
往期推薦:
學嵌入式的你,還不會物件導向??!
全網最適合入門的物件導向程式設計教程:00 物件導向設計方法導論
全網最適合入門的物件導向程式設計教程:01 物件導向程式設計的基本概念
全網最適合入門的物件導向程式設計教程:02 類和物件的 Python 實現-使用 Python 建立類
全網最適合入門的物件導向程式設計教程:03 類和物件的 Python 實現-為自定義類新增屬性
全網最適合入門的物件導向程式設計教程:04 類和物件的Python實現-為自定義類新增方法
全網最適合入門的物件導向程式設計教程:05 類和物件的Python實現-PyCharm程式碼標籤
全網最適合入門的物件導向程式設計教程:06 類和物件的Python實現-自定義類的資料封裝
全網最適合入門的物件導向程式設計教程:07 類和物件的Python實現-型別註解
全網最適合入門的物件導向程式設計教程:08 類和物件的Python實現-@property裝飾器
全網最適合入門的物件導向程式設計教程:09 類和物件的Python實現-類之間的關係
全網最適合入門的物件導向程式設計教程:10 類和物件的Python實現-類的繼承和里氏替換原則
全網最適合入門的物件導向程式設計教程:11 類和物件的Python實現-子類呼叫父類方法
全網最適合入門的物件導向程式設計教程:12 類和物件的Python實現-Python使用logging模組輸出程式執行日誌
全網最適合入門的物件導向程式設計教程:13 類和物件的Python實現-視覺化閱讀程式碼神器Sourcetrail的安裝使用
全網最適合入門的物件導向程式設計教程:全網最適合入門的物件導向程式設計教程:14 類和物件的Python實現-類的靜態方法和類方法
全網最適合入門的物件導向程式設計教程:15 類和物件的 Python 實現-__slots__魔法方法
全網最適合入門的物件導向程式設計教程:16 類和物件的Python實現-多型、方法重寫與開閉原則
全網最適合入門的物件導向程式設計教程:17 類和物件的Python實現-鴨子型別與“file-like object“
全網最適合入門的物件導向程式設計教程:18 類和物件的Python實現-多重繼承與PyQtGraph串列埠資料繪製曲線圖
全網最適合入門的物件導向程式設計教程:19 類和物件的 Python 實現-使用 PyCharm 自動生成檔案註釋和函式註釋
全網最適合入門的物件導向程式設計教程:20 類和物件的Python實現-組合關係的實現與CSV檔案儲存
全網最適合入門的物件導向程式設計教程:21 類和物件的Python實現-多檔案的組織:模組module和包package
全網最適合入門的物件導向程式設計教程:22 類和物件的Python實現-異常和語法錯誤
全網最適合入門的物件導向程式設計教程:23 類和物件的Python實現-丟擲異常
更多精彩內容可看:
給你的 Python 加加速:一文速通 Python 平行計算
一文搞懂 CM3 微控制器除錯原理
肝了半個月,嵌入式技術棧大彙總出爐
電子計算機類比賽的“武林秘籍”
一個MicroPython的開源專案集錦:awesome-micropython,包含各個方面的Micropython工具庫
文件和程式碼獲取:
可訪問如下連結進行對文件下載:
https://github.com/leezisheng/Doc
本文件主要介紹如何使用 Python 進行物件導向程式設計,需要讀者對 Python 語法和微控制器開發具有基本瞭解。相比其他講解 Python 物件導向程式設計的部落格或書籍而言,本文件更加詳細、側重於嵌入式上位機應用,以上位機和下位機的常見串列埠資料收發、資料處理、動態圖繪製等為應用例項,同時使用 Sourcetrail 程式碼軟體對程式碼進行視覺化閱讀便於讀者理解。
相關示例程式碼獲取連結如下:https://github.com/leezisheng/Python-OOP-Demo
正文
當 Python 指令碼發生異常時我們需要捕獲處理它,否則程式會終止執行。捕捉異常可以使用 try/except 語句。try/except 語句用來檢測 try 語句塊中的錯誤,從而讓 except 語句捕獲異常資訊並處理。
如果你不想在異常發生時結束你的程式,只需在 try 裡捕獲它。以下為簡單的 try....except...else 的語法:
try:
<語句>
except <名字>:
<語句>
try 語句的工作原理如下:
-
(1)首先,執行 try 子句(try 和 except 關鍵字之間的(多行)語句)。
-
(2)如果沒有觸發異常,則跳過 except 子句,try 語句執行完畢。
-
(3)如果在執行 try 子句時發生了異常,則跳過該子句中剩下的部分。如果異常的型別與 except 關鍵字後指定的異常相匹配,則會執行 except 子句,然後跳到 try/except 程式碼塊之後繼續執行。
-
(4)如果發生的異常與 except 子句中指定的異常不匹配,則它會被傳遞到外層的 try 語句中;如果沒有找到處理控制代碼,則它是一個未處理異常且執行將停止並輸出一條錯誤訊息。
示例程式碼如下:
class SensorClass(SerialClass):
...
_# 類的初始化_
def __init__(self,port:str = "COM11",id:int = 0,state:int = RESPOND_MODE):
try:
if id <= 0 or id >= 99:
_# 觸發異常後,後面的程式碼就不會再執行_
raise Exception("InvalidIDError:", id)
_# 呼叫父類的初始化方法,super() 函式將父類和子類連線_
super().__init__(port)
self.sensorvalue = 0
self.sensorid = id
self.sensorstate = state
print("Sensor Init")
logging.info("Sensor Init")
except:
_# 當發生異常時,輸出如下語句,提醒使用者重新輸入ID號_
print("Input error ID, Please try id : 0~99")
...
if __name__ == "__main__":
_# 建立感測器類,ID號為100_
s = SensorClass(port = "COM11",id = 100,state = SensorClass.RESPOND_MODE)
如下為執行結果:
以上方式 try-except 語句捕獲所有發生的異常。但這不是一個很好的方式,我們不能透過該程式識別出具體的異常資訊。因為它捕獲所有的異常。
你也可以使用相同的 except 語句來處理多個異常資訊,如下所示:
try:
正常的操作
......................
except(Exception1[, Exception2[,...ExceptionN]]):
發生以上多個異常中的一個,執行這塊程式碼
......................
else:
如果沒有異常執行這塊程式碼
try 語句可以有多個 except 子句來為不同的異常指定處理程式。 但最多隻有一個處理程式會被執行。處理程式只處理對應的 try 子句中發生的異常,而不處理同一 try 語句內其他處理程式中的異常。except 子句可以用帶圓括號的元組來指定多個異常,例如:
... except (RuntimeError, TypeError, NameError):
... pass
示例程式碼如下所示,我們在 SensorClass 感測器類的初始化方法中,加入對輸入 port 埠號資料型別的檢查,如果不是 str 型別,則丟擲 TypeError 異常:
def __init__(self,port:str = "COM11",id:int = 0,state:int = RESPOND_MODE):
try:
_# 判斷輸入埠號是否為str型別_
if type(port) is not str:
raise TypeError("InvalidPortError:",port)
_# 判斷ID號是否在0~99之間_
if id <= 0 or id >= 99:
_# 觸發異常後,後面的程式碼就不會再執行_
_# 當傳遞給函式或方法的引數型別不正確或者引數的值不合法時,會引發此異常。_
raise ValueError("InvalidIDError:",id)
_# 呼叫父類的初始化方法,super() 函式將父類和子類連線_
super().__init__(port)
self.sensorvalue = 0
self.sensorid = id
self.sensorstate = state
print("Sensor Init")
logging.info("Sensor Init")
except TypeError:
_# 當發生異常時,輸出如下語句,提醒使用者重新輸入埠號_
print("Input error com, Please try new com number")
except ValueError:
_# 當發生異常時,輸出如下語句,提醒使用者重新輸入ID號_
print("Input error ID, Please try id : 0~99")
如下為執行結果,可以看到僅捕獲和處理了輸入錯誤 port 型別的異常,而沒有捕獲和處理輸入錯誤範圍的 ID 號的異常:
除了使用 except 塊來處理異常,我們還可以使用 finally 塊來執行一些必要的清理操作。無論是否出現異常,finally 塊中的程式碼都會被執行。如果我們需要在程式碼執行完成之後執行特定的任務(即便是遇到了異常),這將非常有用。一些常見的例子包括:清除開啟的資料庫連線;關閉開啟的檔案;向網路傳送一次關閉握手。finally 語句對於我們在 try 中執行 return 語句也非常重要。finally 中的程式碼仍然會在返回值之前執行。
例如在 FileIOClass 類中,需要讀寫 csc 檔案,基本流程就是開啟了一個 csc 檔案,然後讀取,寫入,最後關閉檔案物件。這是一套常規流程,如果我想捕捉程式碼過程中的異常,又要保證無論是否有異常,最後都必須要關閉檔案。這時候就用到 finally,示例程式碼如下:
class FileIOClass:
def __init__(self,path:str="G:\\Python物件導向程式設計\\Demo\\file.csv"):
'''
初始化csv檔案和列標題
:param path: 檔案路徑和檔名
'''
self.path = path
try:
_# path為輸出路徑和檔名,newline=''是為了不出現空行_
self.csvFile = open(path, "w+", newline='')
_# rowname為列名,index-索引,data-資料_
self.rowname = ['index', 'data']
_# 返回一個writer物件,將使用者的資料在給定的檔案型物件上轉換為帶分隔符的字串_
self.writer = csv.writer(self.csvFile)
_# 寫入csv檔案的列標題_
self.writer.writerow(self.rowname)
except (FileNotFoundError, IOError):
print("Could not open file")
logging.info("Could not open file")
except KeyboardInterrupt:
print("Cancell the file operation")
logging.info("Cancell the file operation")
finally:
self.CloseFile()
我們將檔案路徑改到一個根本不存在的路徑下,初始化 FileIOClass 例項物件,
程式碼如下:
f = FileIOClass(path = "H:\\Python物件導向程式設計\\Demo\\file.csv")
可以看到執行結果中,在發生 IOError 時,執行了 except 中的語句:
在第 16 行中:
16 except (FileNotFoundError, IOError):
表示只要發生 FileNotFoundError 或 IOError 中任意一個就會執行這塊程式碼。
實際上,我們可以用同樣的程式碼一次處理兩個或更多不同的異常。具體格式如下:
except(Exception1[, Exception2[,...ExceptionN]]):
_# 發生以上多個異常中的一個,執行這塊程式碼_
當多種異常同時發生時,我們可以使用如下方式列印出相應異常的類名:
except (FileNotFoundError, IOError) as e:
print("Could not open file",e.__class__.__name__)
logging.info("Could not open file")
我們再次執行程式碼:
有時,當我們捕獲一個異常時,需要用到對 Exception 物件的引用。這通常發生在我們自己定義的有特定引數的異常,此時我們可以使用 as 語句帶上引數,作為輸出的異常資訊引數。示例程式碼如下:
except (FileNotFoundError, IOError) as e:
print("Could not open file",e.__class__.__name__)
print("The exception arguments were", e.args)
logging.info("Could not open file")
執行結果如下,可以看到,在示例中輸出引數為錯誤程式碼(為 2),表示沒有這個檔案或者目錄。
實際上變數接收的異常值通常包含在異常的語句中。在元組的表單中變數可以接收一個或者多個值。元組通常包含錯誤字串,錯誤數字,錯誤位置。