程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python升級之路( Lv8 ) 異常機制

編輯:Python

Python系列文章目錄

第一章 Python 入門
第二章 Python基本概念
第三章 序列
第四章 控制語句
第五章 函數
第六章 面向對象基礎
第七章 面向對象深入
第八章 異常機制


異常機制

  • Python系列文章目錄
  • 前言
  • 一、異常是什麼
    • 解決思路
  • 二、try和except結構
    • try...一個except結構
    • try...多個except結構
    • try...except...else結構
    • try...except...finally結構
  • 三、常見異常
    • 異常匯總
    • 常見異常舉例
  • 四、其他異常相關問題
    • return語句和異常處理問題
    • with上下文管理
    • traceback模塊和生成異常日志
    • 自定義異常類
  • 五、Pycharm開發環境的調試(debug)

前言

在本章, 我們首先會了解什麼是異常: 軟件程序在運行過程中,可能會遇到能使其不能正常運行的問題,我們稱之為異常,英文是: Exception
然後, 我們會了解捕獲異常的四種結構方式,
再然後, 我們梳理常見放的異常
再然後, 我們補充其他關於異常相關的問題,
最後, 我們通過使用 Pycharm 來體會異常的調試過程


一、異常是什麼

程序在運行過程中發生的意外情況,稱為異常,
程序運行時一旦出現了異常,將會導致程序立即終止,異常之後的代碼將無法繼續執行,所以需要對異常進行處理

異常機制本質:

  • 當程序出現異常,程序安全的退出、處理完後繼續執行的機制

python中,引進了很多用來描述和處理異常的類,稱為異常類. 異常類定義中包含了該類異常的信息和對異常進行處理的方法.
下面較為完整的展示了python中內建異常類的繼承層次:

解決思路

異常解決的關鍵:定位
當發生異常時,解釋器會報相關的錯誤信息,並會在控制台打印出相關錯誤信息.
我們只需按照從上到下的順序即可追溯(Trackback)錯誤發生的過程,最終定位引起錯誤的哪一行代碼.

實操代碼

# 測試簡單的0不能做除數異常
# 因為如果假設成立, 則說明 3/0=0 => 可以推導 0*0=3, 因為結果不成立, 因此假設不成立
# a = 3/0
def a():
print("run in a() start! ")
num = 1/0
print("run in a() end! ")
def b():
print("run in b() start! ")
a()
print("run in b() end! ")
def c():
print("run in c() start! ")
b()
print("run in c() end! ")
print("step1")
c()
print("step2")

結果輸出

從打印輸出結果來看, 最底層的方法(eg: a())出錯之後, 會在上層調用的方法位置處拋出異常.
因為錯誤信息以棧的形式輸出, 因此最頂層的調用因為先打印, 所以會先被我們看到. 因此對底層/最有用的信息一般位於最下面.


二、try和except結構

try…一個except結構

這種結構是最常見, 也是最常用的結構

語法結構

try:
被監控的可能引發異常的語句塊
except BaseException [as e]:
異常處理語句塊

注意事項:

  • try 塊包含著可能引發異常的代碼, except 塊則用來捕捉和處理發生的異常
  • 執行的時候,如果 try 塊中沒有引發異常,則跳過 ecept 塊繼續執行後續代碼
  • 執行的時候,如果 try 塊中發生了異常,則跳過 try 塊中的後續代碼,跳到相應的 except 塊中處理異常.
    異常處理完後,繼續執行後續代碼

實操代碼

def a():
print("run in a() start! ")
try:
num = 1 / 0
except BaseException as e:
print("捕獲異常之後執行此處代碼")
print("run in a() end! ")
def b():
print("run in b() start! ")
a()
print("run in b() end! ")
def c():
print("run in c() start! ")
b()
print("run in c() end! ")
print("step1")
c()
print("step2")

結果輸出

try…多個except結構

try…except 的結構可以捕獲所有的異常,工作中也很常見.
但是,一般建議盡量捕獲可能出現的多個異常(按照先子類後父類的順序),並且針對性寫出異常處理代碼
為了避免遺漏可能出現的異常,可以在最後增加 BaseException 。結構如下

語法結構

try:
被監控的、可能引發異常的語句塊
except Exception1:
處理Exception1的語句塊
except Exception2:
處理Exception2的語句塊
[...]
except BaseException:
處理可能遺漏的異常的語句塊

實操代碼

try:
a = input("請輸入被除數: ")
b = input("請輸入除數: ")
result = float(a)/float(b)
print(result)
except ZeroDivisionError:
print("異常: 0不能做除數")
except ValueError:
print("異常: 輸入的必須是數值類型!")
except BaseException as e:
print(e)
print(type(e))

結果輸出

try…except…else結構

在 try…except…else 結構的基礎上增加了 else 塊 .
如果 try 塊中沒有拋出異常,則執行else 塊. 如果 try 塊中拋出異常,則執行 except 塊,不執行 else 塊.

語法結構

try:
被監控的可能引發異常的語句塊
except BaseException [as e]:
異常處理語句塊
else:
沒有拋出異常時執行的語句塊

實操代碼

try:
a = input("請輸入被除數: ")
b = input("請輸入除數: ")
result = float(a)/float(b)
except BaseException as e:
print(e)
else:
print("兩數相除, 結果是:", result)

結果輸出

try…except…finally結構

try…except…finally 結構中, finally 塊無論是否發生異常都會被執行, 通常用來釋放 try 塊中申請的資源

語法結構

try:
被監控的可能引發異常的語句塊
except BaseException [as e]:
異常處理語句塊
finally:
無論是否捕獲異常都會執行的語句塊

實操代碼

try:
a = input("請輸入被除數: ")
b = input("請輸入除數: ")
result = float(a)/float(b)
except BaseException as e:
print(e)
else:
print("兩數相除, 結果是:", result)
finally:
print("我是finally中的語句, 無論發生異常與否, 都執行!")

輸出結果

實操代碼2

try:
f = open("d:/a.txt",'r')
content = f.readline()
print(content)
except BaseException as e:
print(e)
finally:
f.close() #釋放資源. 此處也可能會發生異常。若發生異常,則程序終止,不會繼續往下執行
print("step4")

三、常見異常

異常匯總



常見異常舉例

# Python中的異常都派生自 BaseException 類, 我們測試和列出常見的一些異常, 方便初學者掌握
# 1. SyntaxError :語法錯誤 | SyntaxError: invalid syntax. Perhaps you forgot a comma?
# int a =3
# 2. NameError :嘗試訪問一個沒有申明的變量 | NameError: name 'a' is not defined
# print(a)
# 3. ZeroDivisionError :除數為0錯誤(零除錯誤) | ZeroDivisionError: division by zero
# a = 3 / 0
# 4. ValueError :數值錯誤 | ValueError: could not convert string to float: 'skyII'
# float("skyII")
# 5. TypeError :類型錯誤 | TypeError: unsupported operand type(s) for +: 'int' and 'str'
# 123+"abc"
# 6. AttributeError :訪問對象的不存在的屬性 | AttributeError: 'int' object has no attribute 'sayhi'
# a = 100
# a.sayhi()
# 7. IndexError :索引越界異常 | IndexError: list index out of range
# a = [4, 5, 6]
# a[10]
# 8. KeyError :字典的關鍵字不存在 | KeyError: 'salary'
a = {
'name': "sari", 'age': 18}
a['salary']

四、其他異常相關問題

return語句和異常處理問題

由於 return 有兩種作用:結束方法運行、返回值.
我們一般不把 return放到異常處理結構中,而是放到方法最後.

實操代碼

一般不要將return語句放到try、except、else、finally塊中, 會發生一些意想不到的錯誤. 建議放到方法最後
如上面代碼, 這種寫法就會導致無論是否正確, 都會導致 try內的return無法執行而去執行 finally 內的語句

def testException():
try:
a = input("請輸入被除數: ")
b = input("請輸入除數: ")
result = float(a) / float(b)
return result
except BaseException as e:
print(e)
return "a"
finally:
print("我是finally中的語句, 無論發生異常與否, 都執行!")
return "b"
# return "b" # 正常情況應該放到這裡
print(testException())

結果輸出

with上下文管理

finally 塊由於是否發生異常都會執行,通常我們作為放釋放資源的代碼.
其實,我們可以通過 with 上下文管理,更方便的實現釋放資源的操作.

with 上下文管理可以自動管理資源,在 with 代碼塊執行完畢後自動還原進入該代碼之前的現場或上下文.
不論何種原因跳出 with塊,不論是否有異常,總能保證資源正常釋放.
極大的簡化了工作,在文件操作、網絡通信相關的場合非常常用.

語法結構

with context_expr [ as var]:
語句塊

實操代碼

# 【示例】 with 上下文管理文件操作
with open("d:/dd.txt") as f:
for line in f:
print(line)

traceback模塊和生成異常日志

我們可以利用 traceback.print_exc(file=f), 將異常日志輸出到日志文件中

# traceback模塊和生成異常日志
import traceback
try:
print("step1")
num = 1 / 0
except:
# traceback.print_exc() # 直接輸出錯誤調用記錄
with open("d:/a.log", "a") as f: # 使用 traceback 將異常信息寫入日志文件
traceback.print_exc(file=f)

自定義異常類

程序開發中,有時候我們也需要自己定義異常類.
自定義異常類一般都是運行時異常,通常繼承 Exception 或其子類即可.
命名一般以Error 、 Exception 為後綴. 自定義異常由 raise 語句主動拋出.

實操代碼

# 【示例】自定義異常類和raise語句
class AgeError(Exception):
def __init__(self, errorInfo):
Exception.__init__(self)
self.errorInfo = errorInfo
def __str__(self):
return str(self.errorInfo) + ", 年齡錯誤! 應該在 1-150之間!"
# 測試代碼
if __name__ == "__main__": # 如果為True, 則模塊是作為獨立文件運行, 可以執行測試代碼
age = int(input("輸入一個年齡: "))
if age < 1 or age > 150:
raise AgeError(age)
else:
print("正常的年齡: ", age)

結果輸出


五、Pycharm開發環境的調試(debug)

程序運行到此處,暫時掛起,停止執行。我們可以詳細在此時觀察程序的運行情況,方便做出進一步的判斷

調試步驟

  1. 設置斷點:
    在行號後面單擊即可增加斷點。在斷點上再單擊即可取消斷點

  2. 進入調試視圖
    我們通過如下三種方式都可以進入調試視圖:
    單擊工具欄上的按鈕 / 右鍵單擊編輯區,點擊: debug ‘模塊名’ / 快捷鍵: shift+F9

  3. 進入調試視圖後,布局如下:
    左側為“浏覽幀”:調試器列出斷點處,當前線程正在運行的方法,每個方法對應一個“棧幀”. 最上面是當前斷點所處的方法.
    變量值觀察區: 調試器列出了斷點處所在方法相關的變量值. 我們可以通過它,查看變量的值的變化.

  4. 調試操作區

    我們通過上圖中的按鈕進行調試操作,它們的含義如下:



  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved