日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

python语句解释_深入理解python with 语句

發(fā)布時間:2023/12/15 python 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python语句解释_深入理解python with 语句 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

深入理解python with 語句

python中with 語句作為try/finally 編碼范式的一種替代, 適用于對資源進行訪問的場合,確保不管使用過程中是否發(fā)生異常都會執(zhí)行必要的”清理”操作,釋放資源,比如文件使用后自動關(guān)閉、線程中鎖的自動獲取和釋放等

1. 使用with打開文件

你應(yīng)該見過下面這種打開文件的方式

with open('data', 'r', encoding='utf-8') as f:

data = f.readlines()

上面的寫法,與下面的寫法在最終效果上是一致的

f = open('data', 'r', encoding='utf-8')

try:

data = f.readlines()

except:

pass

finally:

f.close()

對比兩段代碼不難發(fā)現(xiàn),使用with語句時,代碼更加簡潔,而且不用主動關(guān)閉文件,在with語句體退出時,會自動關(guān)閉文件,即便with語句體中發(fā)生了異常。

2. 上下文管理器和with 語句有關(guān)的概念

想要理解with語句,就必須先理解以下幾個概念

2.1 上下文管理協(xié)議

簡單來說,就是實現(xiàn)兩個方法,__enter__() 和__exit__()

2.2 上下文管理器

實現(xiàn)了__enter__() 和__exit__()的對象就是上下文管理器

2.3 運行時上下文

由上下文管理器創(chuàng)建,在with語句體代碼執(zhí)行前,通過__enter__()進入,語句體代碼執(zhí)行結(jié)束后,通過__exit__()退出

2.4 上下文表達式

在with關(guān)鍵字后面的表達式,表達式返回上下文管理器對象

2.5 語句體

with語句包裹起來的代碼

3. 使用with語句控制線程鎖的釋放

使用with不僅能夠自動的關(guān)閉打開的文件對象,還可以自動的釋放線程鎖,這樣可以避免死鎖的發(fā)生,在python多線程---線程鎖一文中,為避免多個線程同時對一個變量對象進行修改,在關(guān)鍵語句上加了線程鎖

def worker():

time.sleep(1)

global a

for i in range(100000):

m_lock.acquire() # 加鎖

a += 1

m_lock.release() # 釋放鎖

如果你忘記了寫m_lock.release() 對鎖進行釋放,那么這將導(dǎo)致其他線程永遠(yuǎn)也無法獲取到線程鎖,這樣就形成了死鎖,上面的代碼在acquire之后,使用release釋放所,使用with語句,可以更加優(yōu)雅的實現(xiàn)加鎖和釋放鎖的操作。

def worker():

time.sleep(1)

global a

for i in range(100000):

with m_lock:

a += 1

4. 同時打開多個文件

許多人都不知道,with語句可以同時打開多個文件,這樣做可以減少代碼的縮進,讓代碼的編寫更加容易,兩個open語句之間用逗號分隔即可。

with open('a1', 'w')as f1, open('a2', 'w')as f2:

f1.write('a')

f2.write('b')

5. 自定義上下文管理器

在調(diào)試程序性能時,如果只是想知道某個函數(shù)的執(zhí)行時長,可以使用一個可以統(tǒng)計函數(shù)運行時長的裝飾器進行處理,但程序往往很復(fù)雜,一段代碼里,要做很多操作,不只是調(diào)用了一個函數(shù),也可能存在循環(huán),因此,單純的知道某個函數(shù)的執(zhí)行時長,不能幫助我們更好的了解程序的性能。

我們需要針對某個代碼段進行時間統(tǒng)計,知道這一段代碼的執(zhí)行時長對我們很有幫助。你可以使用time.time()方法在代碼段開始時獲取到時間,在結(jié)束時再次獲取到時間,兩個時間做差就可以得到這個代碼段的運行時長,這種操作方式寫起來很麻煩,如果有多處代碼段需要統(tǒng)計,就得寫多次,很不方便。

下面是一個可以統(tǒng)計代碼段運行時長的上下文管理器

import time

class ProTime(object):

def __init__(self, tag=''):

self.tag = tag

def __enter__(self):

self.start_time = time.time()

def __exit__(self, exc_type, exc_val, exc_tb):

self.end_time = time.time()

time_diff = self.end_time - self.start_time

msg = "代碼段{tag}運行時長{time_diff}".format(tag=self.tag, time_diff=time_diff)

print(msg)

with ProTime('first') as pt:

# 這里是你要統(tǒng)計運行時長的代碼塊

time.sleep(1)

with ProTime('second') as pt:

# 這里是你要統(tǒng)計運行時長的代碼塊

time.sleep(2)

理解這段代碼的關(guān)鍵之處,在with語句所包裹的語句體執(zhí)行之前,先要執(zhí)行__enter__方法,語句體執(zhí)行結(jié)束之后,不論是否有異常,都要執(zhí)行__exit__,在__exit__方法里,三個參數(shù)提供了異常的全部信息,如果你想處理異常,可以在這個方法里做處理。

__init__ 方法有一個tag參數(shù),設(shè)置這個參數(shù)的目的,是為了在輸出信息里區(qū)分多個代碼塊,如果不想設(shè)置這個tag,可以考慮對這個上下文管理器進行修改,通過調(diào)用棧獲得調(diào)用信息,準(zhǔn)確的指出是哪個代碼段的執(zhí)行時長。

修改后的上下文管理器如下

import time

import sys

class ProTime(object):

def __init__(self, tag=''):

frame = sys._getframe()

tag_frame = frame.f_back

self.lineno = tag_frame.f_lineno

self.filename = tag_frame.f_code.co_filename

self.tag = tag

def __enter__(self):

self.start_time = time.time()

def __exit__(self, exc_type, exc_val, exc_tb):

self.end_time = time.time()

time_diff = self.end_time - self.start_time

if self.tag:

msg = "代碼段{tag}運行時長{time_diff}".format(tag=self.tag, time_diff=time_diff)

else:

msg = "文件{filename} 第 {lineno} 行代碼塊執(zhí)行時長{time_diff}".format(filename=self.filename, lineno=self.lineno, time_diff=time_diff)

print(msg)

with ProTime('first') as pt:

# 這里是你要統(tǒng)計運行時長的代碼塊

time.sleep(1)

with ProTime() as pt:

# 這里是你要統(tǒng)計運行時長的代碼塊

time.sleep(2)

def test():

with ProTime() as pt:

# 這里是你要統(tǒng)計運行時長的代碼塊

time.sleep(1)

test()

總結(jié)

以上是生活随笔為你收集整理的python语句解释_深入理解python with 语句的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。