Python 錯誤處理詳解
Python 寫代碼時,錯誤是常有的事。為了讓程序更健壯,我們需要學會如何處理這些錯誤。這篇文章會帶你從零開始了解 Python 的錯誤處理。
參考文章:
- 什么是異常?
- 常見的 Python 異常類型
- 基本的 try-except 結(jié)構
- 捕獲特定異常
- 使用 else 和 finally
- 拋出異常
- 自定義異常
- 錯誤處理的最佳實踐
1. 什么是異常?
異常(Exception)就是程序運行時發(fā)生的錯誤,比如試圖打開一個不存在的文件、除以零或者輸入了非法數(shù)據(jù)。Python 會拋出異常來告訴你“嘿,這里出問題了!”。如果不處理,程序會直接崩潰,打印一堆錯誤信息(就是 traceback)。
異常處理的核心是用代碼“捕獲”這些錯誤,防止程序崩掉,還能給用戶友好的提示。
2. 常見的 Python 異常類型
Python 內(nèi)置了很多異常類型,了解它們能幫你更好地處理問題。以下是一些常見的異常:
ZeroDivisionError:除以零時觸發(fā)。FileNotFoundError:試圖打開不存在的文件。ValueError:函數(shù)接收到不合適的參數(shù),比如把字符串傳給int()。TypeError:類型錯誤,比如試圖把字符串和整數(shù)相加。IndexError:列表索引超出范圍。KeyError:訪問字典中不存在的鍵。
這些異常都是 Python 的內(nèi)置類,繼承自 Exception 類。你可以在代碼中捕獲它們。
3. 基本的 try-except 結(jié)構
Python 用 try-except 塊來處理異常。基本思路是:把可能出錯的代碼放進 try 塊,如果出錯了,就跳到 except 塊執(zhí)行。
來看個簡單的例子:
try:
num = int(input("請輸入一個數(shù)字: "))
result = 10 / num
print(f"10 除以 {num} 等于 {result}")
except:
print("出錯了!可能輸入了非法數(shù)字或除以零。")
運行這段代碼:
- 如果用戶輸入一個合法數(shù)字,比如
5,程序會打印10 除以 5 等于 2.0。 - 如果輸入了非數(shù)字(比如
"abc")或0,程序會跳到except塊,打印錯誤提示,而不會崩潰。
這個 except 是個“通吃”模式,捕獲所有異常。但最好別這樣用,因為你不知道具體出了啥問題。接下來我們改進它。
4. 捕獲特定異常
與其捕獲所有異常,不如只捕獲你關心的特定異常類型。這樣能更精準地處理問題。Python 允許在 except 后指定異常類型。
改寫上面的例子:
try:
num = int(input("請輸入一個數(shù)字: "))
result = 10 / num
print(f"10 除以 {num} 等于 {result}")
except ValueError:
print("請輸入一個合法的數(shù)字!")
except ZeroDivisionError:
print("不能除以零!")
現(xiàn)在:
- 如果輸入
"abc",會觸發(fā)ValueError,打印“請輸入一個合法的數(shù)字!”。 - 如果輸入
0,會觸發(fā)ZeroDivisionError,打印“不能除以零!”。 - 其他異常(比如
KeyboardInterrupt)不會被捕獲,程序會照常報錯。
你可以捕獲多個異常,也可以把異常對象保存下來,查看具體錯誤信息:
try:
num = int(input("請輸入一個數(shù)字: "))
result = 10 / num
except ValueError as e:
print(f"輸入錯誤: {e}")
except ZeroDivisionError as e:
print(f"除零錯誤: {e}")
這里 as e 把異常對象存到變量 e,可以打印更詳細的錯誤信息。
5. 使用 else 和 finally
try-except 還有兩個好用的伙伴:else 和 finally。
else:如果try塊沒出錯,就執(zhí)行else塊。適合放那些依賴try塊成功的代碼。finally:不管try塊有沒有出錯,finally塊都會執(zhí)行。常用來做清理工作,比如關閉文件。
來看個例子:
try:
num = int(input("請輸入一個數(shù)字: "))
result = 10 / num
except ValueError:
print("請輸入合法數(shù)字!")
except ZeroDivisionError:
print("不能除以零!")
else:
print(f"計算成功!結(jié)果是: {result}")
finally:
print("程序結(jié)束,清理完成!")
運行效果:
- 輸入
5:打印“計算成功!結(jié)果是: 2.0”和“程序結(jié)束,清理完成!”。 - 輸入
"abc":打印“請輸入合法數(shù)字!”和“程序結(jié)束,清理完成!”。 - 輸入
0:打印“不能除以零!”和“程序結(jié)束,清理完成!”。
finally 特別適合確保資源被正確釋放,比如:
try:
file = open("data.txt", "r")
content = file.read()
except FileNotFoundError:
print("文件沒找到!")
else:
print(f"文件內(nèi)容: {content}")
finally:
try:
file.close()
print("文件已關閉")
except NameError:
print("文件從未打開,無需關閉")
這里 finally 確保文件被關閉,即使文件沒找到(導致 file 未定義)也能安全處理。
6. 拋出異常
有時候你想主動拋出異常,比如檢查到用戶輸入不符合要求。可以用 raise 關鍵字拋出異常。
例子:
def divide(a, b):
if b == 0:
raise ZeroDivisionError("除數(shù)不能為零!")
return a / b
try:
result = divide(10, 0)
except ZeroDivisionError as e:
print(f"錯誤: {e}")
運行會打印“錯誤: 除數(shù)不能為零!”。你可以用 raise 拋出任何內(nèi)置異常,或者直接用 raise Exception("自定義消息")。
還可以“重新拋出”異常:
try:
num = int(input("請輸入一個數(shù)字: "))
except ValueError as e:
print(f"輸入錯誤: {e}")
raise # 重新拋出原異常
這樣會在處理完錯誤后,繼續(xù)把異常拋給上層調(diào)用者。
7. 自定義異常
當內(nèi)置異常不夠用時,你可以定義自己的異常類。自定義異常通常繼承自 Exception 類。
例子:
class CustomValueError(Exception):
"""自定義異常,用于值不符合要求"""
pass
def check_age(age):
if age < 0 or age > 150:
raise CustomValueError("年齡必須在0到150之間!")
return age
try:
age = check_age(200)
except CustomValueError as e:
print(f"錯誤: {e}")
運行會打印“錯誤: 年齡必須在0到150之間!”。自定義異常讓代碼更清晰,尤其在復雜項目中。
8. 錯誤處理的最佳實踐
最后,分享一些寫錯誤處理代碼的建議:
- 捕獲特定異常:別用“通吃”的
except,盡量指定具體的異常類型。 - 提供清晰的錯誤信息:用戶看到錯誤時,應該知道問題出在哪,怎么解決。
- 用 else 和 finally 合理組織代碼:
else放依賴try成功的邏輯,finally放清理工作。 - 別濫用異常:異常是用來處理“異常情況”的,別用它來控制正常流程(比如代替
if判斷)。 - 記錄錯誤日志:在實際項目中,用
logging模塊記錄異常,方便調(diào)試。
例子(帶日志):
import logging
logging.basicConfig(level=logging.ERROR, filename="app.log")
try:
num = int(input("請輸入一個數(shù)字: "))
result = 10 / num
except ValueError as e:
logging.error(f"輸入錯誤: {e}")
print("請輸入合法數(shù)字!")
except ZeroDivisionError as e:
logging.error(f"除零錯誤: {e}")
print("不能除以零!")
else:
print(f"結(jié)果: {result}")
finally:
print("程序結(jié)束!")
這個例子會把錯誤記錄到 app.log 文件,方便排查問題。

浙公網(wǎng)安備 33010602011771號