Python中?try?/?except?/?else?/?finally?異常處理方法詳解
1. 基本結(jié)構(gòu)
try: # 可能會拋出異常的代碼 except SomeException as e: # 捕獲并處理異常 else: # 如果 try 中代碼沒有異常,就執(zhí)行這里 finally: # 無論是否發(fā)生異常,最后都會執(zhí)行這里
2. 各部分的作用
try
- 用途:包含可能發(fā)生異常的代碼段。
- 如果代碼沒有異常,則
except
不會被執(zhí)行,直接進入else
(如果有的話)。 - 如果有異常,則轉(zhuǎn)到對應的
except
。
except
- 用途:捕獲并處理異常。
- 可以寫多個
except
,匹配不同的異常類型。
示例:
try: x = int("abc") # 會觸發(fā) ValueError except ValueError: print("捕獲到 ValueError") except TypeError: print("捕獲到 TypeError")
else
- 用途:只有當 try 中沒有發(fā)生任何異常時 才會執(zhí)行。
- 常用于把 不需要異常保護的邏輯 放在這里,讓
try
中的代碼盡量簡潔。
示例:
try: result = 10 / 2 except ZeroDivisionError: print("除零錯誤") else: print("計算成功,結(jié)果是:", result)
運行結(jié)果:
計算成功,結(jié)果是: 5.0
finally
- 用途:無論是否發(fā)生異常,都會執(zhí)行。
- 常用于資源釋放、文件關閉、鎖釋放等。
示例:
try: f = open("test.txt", "r") data = f.read() except FileNotFoundError: print("文件不存在") else: print("讀取成功") finally: print("執(zhí)行 finally") if 'f' in locals() and not f.closed: f.close()
3. 執(zhí)行流程總結(jié)
情況 | try | except | else | finally |
---|---|---|---|---|
沒有異常 | 執(zhí)行 | 跳過 | 執(zhí)行 | 執(zhí)行 |
有異常,匹配到 | 執(zhí)行到異常處中斷 | 執(zhí)行 | 跳過 | 執(zhí)行 |
有異常,未匹配到 | 執(zhí)行到異常處中斷 | 不執(zhí)行 | 不執(zhí)行 | 執(zhí)行(然后異常繼續(xù)向上拋出) |
4. 常見用法
(1)多個except
try: x = int("abc") except ValueError: print("數(shù)值錯誤") except Exception as e: print("其他異常:", e)
(2)捕獲多個異常
try: x = int("abc") except (ValueError, TypeError) as e: print("捕獲到異常:", e)
(3)用else處理后續(xù)邏輯
try: num = int("123") except ValueError: print("轉(zhuǎn)換失敗") else: print("轉(zhuǎn)換成功,結(jié)果是:", num)
(4)finally釋放資源
try: f = open("data.txt", "r") data = f.read() except FileNotFoundError: print("文件沒找到") finally: print("關閉文件") if 'f' in locals() and not f.closed: f.close()
5. 容易踩的坑
- finally 中的 return 會覆蓋異常
def foo(): try: return 1 finally: return 2 print(foo()) # 輸出 2,而不是 1
說明:finally
里的 return
、break
、continue
都會覆蓋 try/except/else
的返回值或異常。
過度使用 try
- 最佳實踐:只把 可能發(fā)生異常的最小代碼塊 放進
try
,不要把一大段邏輯全包進去。
- 最佳實踐:只把 可能發(fā)生異常的最小代碼塊 放進
6.常用場景示例
下面 6 個示例覆蓋了:
- 文件操作
- 用戶輸入
- 網(wǎng)絡請求
- 多異常捕獲
- 數(shù)據(jù)庫操作
- 臨時文件清理
示例 1:文件讀取(帶finally關閉資源)
try: f = open("test.txt", "r") data = f.read() except FileNotFoundError: print("文件不存在") else: print("文件內(nèi)容:", data) finally: if 'f' in locals() and not f.closed: f.close() print("文件已關閉")
應用場景:文件操作時,確保資源一定會被關閉。
示例 2:用戶輸入校驗
try: num = int(input("請輸入一個整數(shù): ")) except ValueError: print("輸入無效,請輸入整數(shù)!") else: print("你輸入的整數(shù)是:", num)
應用場景:處理用戶輸入時防止格式錯誤。
示例 3:網(wǎng)絡請求(簡化版)
import requests try: response = requests.get("https://httpbin.org/get") data = response.json() except requests.RequestException as e: print("請求失敗:", e) else: print("請求成功,返回數(shù)據(jù):", data) finally: print("請求結(jié)束")
應用場景:網(wǎng)絡請求一定要有異常處理,否則一旦超時或斷網(wǎng)就會崩潰。
示例 4:多個異常捕獲
try: x = int("abc") # ValueError y = 10 / 0 # ZeroDivisionError except ValueError: print("數(shù)值轉(zhuǎn)換錯誤") except ZeroDivisionError: print("除零錯誤") except Exception as e: print("其他錯誤:", e)
應用場景:針對不同錯誤分類處理,更清晰。
示例 5:數(shù)據(jù)庫操作(帶finally釋放連接)
class FakeDB: def connect(self): print("連接數(shù)據(jù)庫") def close(self): print("關閉數(shù)據(jù)庫") def query(self): return [1, 2, 3] db = FakeDB() try: db.connect() result = db.query() except Exception as e: print("查詢失敗:", e) else: print("查詢結(jié)果:", result) finally: db.close()
應用場景:數(shù)據(jù)庫、消息隊列、Socket等操作中保證資源一定釋放。
示例 6:finally保證清理臨時文件
import os try: with open("temp.txt", "w") as f: f.write("臨時數(shù)據(jù)") raise RuntimeError("模擬出錯") except RuntimeError as e: print("捕獲到異常:", e) finally: if os.path.exists("temp.txt"): os.remove("temp.txt") print("臨時文件已刪除")
應用場景:程序中斷時確保臨時文件、緩存不會遺留。
7. 總結(jié)口訣
try
:放可能出錯的代碼except
:出錯就處理else
:沒出錯才執(zhí)行finally
:一定會執(zhí)行
高級應用內(nèi)容
高級應用主要涉及:
- 異常鏈:處理后再拋出
- 自定義異常:模塊化項目常用
- 上下文管理器:優(yōu)雅封裝
try/finally
- 邏輯分層:
else
只放成功邏輯 - finally 覆蓋陷阱:調(diào)試必知
- contextlib.suppress:優(yōu)雅忽略異常
- 事務回滾:數(shù)據(jù)庫/分布式系統(tǒng)
- 多線程異常處理:防止異常丟失
下面分別舉例說明,具體內(nèi)容如下:
1. 捕獲并重新拋出異常(異常鏈)
有時需要先處理一下,再把異常繼續(xù)拋給上層:
def process_data(data): try: return int(data) except ValueError as e: print("日志記錄:數(shù)據(jù)轉(zhuǎn)換失敗 ->", e) raise # 重新拋出異常,讓上層調(diào)用者知道
應用場景:日志記錄、錯誤追蹤。
2. 自定義異常類
在工程里,為了更清晰區(qū)分錯誤類型,常會定義自家異常:
class DataFormatError(Exception): pass def load_data(data): if not isinstance(data, dict): raise DataFormatError("數(shù)據(jù)必須是字典類型") try: load_data("not_dict") except DataFormatError as e: print("捕獲到自定義異常:", e)
應用場景:大型項目中,給模塊定義專屬錯誤類型,便于精確捕獲。
3.with上下文管理器的異常處理
上下文管理器的 __exit__
方法可以接收異常,并決定是否吞掉:
class Demo: def __enter__(self): print("進入上下文") return self def __exit__(self, exc_type, exc_val, exc_tb): print("退出上下文") if exc_type: print("捕獲異常:", exc_type, exc_val) return True # 返回 True 表示異常已處理,不會再拋出 with Demo(): print("運行中...") raise ValueError("測試異常") print("程序繼續(xù)執(zhí)行")
應用場景:數(shù)據(jù)庫事務、文件操作、鎖等,結(jié)合 try/finally
自動化資源管理。
4.try/except/else結(jié)合邏輯分層
讓 try
只負責可能出錯的部分,后續(xù)邏輯放到 else
,保持結(jié)構(gòu)清晰:
try: f = open("config.json") config = f.read() except FileNotFoundError: print("配置文件缺失") else: print("配置文件加載成功") finally: if 'f' in locals(): f.close()
應用場景:避免把無關代碼放進 try
,提高可讀性。
5.finally中的清理 vs. 異常屏蔽
注意:如果 finally
里有 return/raise
,會覆蓋原異常:
def test(): try: 1 / 0 except ZeroDivisionError: print("捕獲到異常") raise finally: return "finally 覆蓋了異常" print(test()) # 輸出 "finally 覆蓋了異常"
應用場景:調(diào)試時要小心,避免無意中吞掉異常。
6.contextlib.suppress—— 優(yōu)雅忽略異常
Python 內(nèi)置的工具類,可以用來代替 try/except/pass
:
import contextlib with contextlib.suppress(FileNotFoundError): with open("no_such_file.txt") as f: data = f.read() print("即使文件不存在,程序也能繼續(xù)運行")
應用場景:當你明確不關心某些異常時,代碼更簡潔。
7. 異常和事務(數(shù)據(jù)庫/分布式)
很多數(shù)據(jù)庫驅(qū)動會在 try/except/finally
中實現(xiàn)事務控制:
try: db.begin() db.insert("users", {"id": 1, "name": "Alice"}) db.commit() except Exception as e: db.rollback() print("事務失敗:", e)
應用場景:保證數(shù)據(jù)一致性。
8. 異常與多線程
在多線程中,子線程的異常不會自動傳遞到主線程,需要顯式捕獲:
import threading def worker(): try: 1 / 0 except Exception as e: print("子線程異常:", e) t = threading.Thread(target=worker) t.start() t.join()
應用場景:多線程/異步編程中異常管理。
總結(jié)
到此這篇關于Python中try/except/else/finally異常處理方法詳解的文章就介紹到這了,更多相關Python try/except/else/finally異常內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
用Python登錄Gmail并發(fā)送Gmail郵件的教程
這篇文章主要介紹了用Python登錄Gmail并發(fā)送Gmail郵件的教程,利用了Python的SMTP庫,代碼非常簡單,需要的朋友可以參考下2015-04-04PyQt5 QSerialPort子線程操作的實現(xiàn)
這篇文章主要介紹了PyQt5 QSerialPort子線程操作的實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-04-04Python實現(xiàn)Excel做表自動化的最全方法合集
Microsoft?Excel?是一款強大的辦公工具,廣泛用于數(shù)據(jù)分析、報告制作、預算管理等各種任務,本文將深入探討如何使用?Python?進行?Excel?表格的自動化,需要的可以參考下2024-02-02django 使用 request 獲取瀏覽器發(fā)送的參數(shù)示例代碼
這篇文章主要介紹了django 使用 request 獲取瀏覽器發(fā)送的參數(shù)示例代碼,獲取數(shù)據(jù)有四種方式,具體內(nèi)容詳情大家跟隨腳本之家小編一起看看吧2018-06-06