Python 的 with 語句詳解

2022-10-05 00:09:18 字數 3696 閱讀 2584

一、簡介

with是從pytho程式設計客棧n 2.5 引入的乙個新的語法,更準確的說,是一種上下文的管理協議,用於簡化try…except…finally的處理流程。with通過__enter__方法初始化,然後在__exit__中做善後以及處理異常。對於一些需要預先設定,事後要清理的一些任務,with提供了一種非常方便的表達。

with的基本語法如下,expr是乙個任意表示式,var是乙個單一的變數(可以是tuple),」as var」是可選的。

複製** **如下:

with expr as var:

block

根據pep 343的解釋,with…as…會被翻譯成以下語句:

複製** **如下:

mgr = (expr)

exit = type(mgr).__exit__  # not calling it yet

value = type(mgr).__enter__(mgr)

exc = true

try:

try:

var = value  # only if "as var" 程式設計客棧is present

block

except:

# the exceptional case is handled here

exc = false

if not exit(mgr, *sys.exc_info()):

raise

# the exception is swallowed if exit() returns true

finally:

# the normal and non-local-goto cases are handled here

if exc:

exit(mgr, none, none, none)

為什麼這麼複雜呢?注意finally中的**,需要block被執行後才會執行finally的清理工作,因為當expr執行時丟擲異常,訪問mgr.exit執行就會報attributeerror的錯誤。

二、實現方式

根據前面對with的翻譯可以看到,被with求值的物件必須有乙個__enter__方法和乙個__exit__方法。稍微看乙個檔案讀取的例子吧,注意在這裡我們要解決2個問題:檔案讀取異常,讀取完畢後關閉檔案控制代碼。用try…except一般會這樣寫:

複製** **如下:

f = open('/tmp/tmp.txt')

try:

for line in f.readlines():

print(line)

finally:

f.close()

注意我們這裡沒有處理檔案開啟失敗的ioerror,上面的寫法可以正常工作,但是對於每個開啟的檔案,我們都要手動關閉檔案控制代碼。如果要使用with來實現上述功能,需要需程式設計客棧要乙個**類:

複製** **如下:

class opened(object):

def __init__(self, name):

self.handle = open(name)

def __enter__(self):

return self.handle

def __exit__(self, type, value, trackback):

self.handle程式設計客棧.close()

with opened('/tmp/a.txt') as f:

for line in f.readlines():

print(line)

注意我們定了乙個名字叫opened的輔助類,並實現了__enter__和__exit__方法,__enter__方法沒有引數,__exit__方法的3個引數,分別代表異常的型別、值、以及堆疊資訊,如果沒有異常,3個入參的值都為none。

如果你不喜歡定義class,還可以用python標準庫提供的contextlib來實現:

複製** **如下:

from contextlib import contextmanager

@contextmanager

def opened(name):

f = open(name)

try:

yield f

finally:

f.close()

with opened('/tmp/a.txt') as f:

for line in f.readlines():

print(line)

使用contextmanager的函式,yield只能返回乙個引數,而yield後面是處理清理工作的**。在我們讀取檔案的例子中,就是關閉檔案控制代碼。這裡原理上和我們之前實現的類opened是相同的,有興趣的可以參考一下contextmanager的源**。

三、應用場景

廢話了這麼多,那麼到底那些場景下該使用with,有沒有一些優秀的例子?當然啦,不然這篇文章意義何在。以下摘自pep 343。

乙個確保**執行前加鎖,執行後釋放鎖的模板:

複製** **如下:

@contextmanager

def locked(lock):

lock.acquire()

try:

yield

finally:

lock.release()

with locked(mylock):

# code here executes with mylock held.  the lock is

# guaranteed to be released when the block is left (even

# if via return or by an uncaught exception).

資料庫事務的提交和回滾:

複製** **如下:

@contextmanager

def transaction(db):

db.begin()

try:

yield none

except:

db.rollback()

raise

else:

db.commit()

重定向stdout:

複製** **如下:

@contextmanager

def stdout_redirected(new_stdout):

s**e_stdout = sys.stdout

sys.stdout = new_stdout

try:

yield none

finally:

sys.stdout = s**e_stdout

with opened(filename, "w") as f:

with stdout_redirected(f):

print "hello world"

注意上面的例子不是執行緒安全的,再多執行緒環境中要小心使用。

四、總結

with是對try…expect…finally語法的一種簡化,並且提供了對於異常非常好的處理方式。在python有2種方式來實現with語法:class-based和decorator-based,2種方式在原理上是等價的,可以根據具體場景自己選擇。

with最初起源於一種block…as…的語法,但是這種語法被很多人所唾棄,最後誕生了with,關於這段歷史依然可以去參yqybzzbyc考pep-343和pep-340

本文標題: python 的 with 語句詳解

本文位址:

詳解Python中break語句的用法

在python中的break語句終止當前迴圈,繼續執行下乙個語句,就像c語言中的break一樣。break最常見的用途是當一些外部條件被觸發,需要從乙個迴圈中斷退出。break語句可以在while和for迴圈使用。如果正在使用巢狀迴圈 即乙個迴圈裡內嵌另乙個迴圈 break語句可以用於停止最內層迴圈...

python的語句 Python的語句

python中的兩種語句 1 if條件控制語句 格式 if a int input 請輸入第乙個數 b int input 請輸入第二個數 if a b print a比b小 if else a int input 請輸入第乙個數 b int input 請輸入第二個數 if a b print a...

Python中break語句用法詳解!

這篇文章主要介紹了詳解python中break語句的用法,是python入門的撥出知識,需要的朋友可以參考下 在python中的break語句終止當前迴圈,繼續執行下乙個語句,就像c語言中的break一樣。break最常見的用途是當一些外部條件被觸發,需要從乙個迴圈中斷退出。break語句可以在wh...