[英]How are exceptions caught with context manager in python
我有以下方法來建立與數據庫的連接並最終將其拆除。 函數看起來像這樣
def read_db(self, sql_statement):
conn = pymysql.connect(host=self.h,user=self.u,passwd=self.pw,
db=self.db,port=self.p)
try:
with conn.cursor() as cur:
cur.execute(sql_statement)
doStuffGeneratingException()
except Exception:
cur.rollback()
raise
finally:
conn.close()
現在,如果我不得不用上下文管理器替換它,我認為它看起來像
@contextmanager
def setup_sql():
conn = pymysql.connect(host=self.h,user=self.u,passwd=self.pw,
db=self.db,port=self.p)
yield conn.cursor()
connection.cursor().close()
self.connection.close()
def read_db(self, sql_statement):
with setup_sql() as cur:
try:
cur.execute(sql_statement)
doStuffGeneratingException()
except:
cur.rollback()
raise
現在我的問題是
contextmanager
執行pymysql.connect(...)
語句時發生錯誤,將如何處理? 它將如何冒泡到調用函數?with
實現中的doStuffGeneratingException()
出現異常會發生什么? 控件會先到setup_sql
執行yield
之后的語句嗎?1,有點。 整個 try/except 需要另一個級別的縮進。
def read_db(self, sql_statement):
with setup_sql() as cur:
try:
cur.execute(sql_statement)
doStuffGeneratingException()
except:
cur.rollback()
raise
2、代碼中沒有處理任何地方的錯誤,因此python本身會報告異常並停止執行。 它可以在您選擇的任何地方捕獲。 在 setup_sql() 和 read_db() 內部都是可行的,但是如果您打算對此做些什么,通常您希望盡可能接近引發它們的異常處理。 要在 read_db() 中執行另一個 try: 塊,您需要使用 setup_sql():
def read_db(self, sql_statement):
try:
with setup_sql() as cur:
try:
cur.execute(sql_statement)
doStuffGeneratingException()
except:
# gets exceptions thrown by cur.execute() and doStuffGeneratingException()
# will not process context manager statements after yield if flow doesn't continue in this function past this except block
cur.rollback()
raise
except:
# gets exceptions thrown by `with setup_sql() as cur:`
# again none of the statements within the context manager after the statement that raises an exception will be executed
pass
3,沒有。 一個例外是立即“返回”,它將擊中您的回滾,而重新引發它將中止您的 with 塊。 如果您希望上下文管理器完成,請捕獲異常並處理它們而無需重新引發。 如果您需要在那里引發異常並希望上下文管理器完成其工作,請設置一個標志變量並在上下文管理器關閉后引發或以另一種方式重構您的代碼以實現該目標。
我相信您實際上可以通過在方法內部的yield
語句周圍放置 try / except / finally 來封裝上下文管理器中的錯誤處理,例如:
from contextlib import contextmanager
@contextmanager
def setup_sql():
conn = pymysql.connect(host=self.h,user=self.u,passwd=self.pw,
db=self.db,port=self.p)
cursor = conn.cursor()
try:
yield cursor
except Exception:
cursor.rollback()
raise
finally:
cursor.close()
conn.close()
def read_db(self, sql_statement):
with setup_sql() as cur:
cur.execute(sql_statement)
doStuffGeneratingException()
我還沒有嘗試過這個,但是我在另一個 SO 問題上遇到了這個評論,該問題鏈接到關於@contextmanager的文檔,解釋了它是如何工作的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.