偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Python編程:輕松搞透上下文管理器(Context Manager)

開(kāi)發(fā) 前端
本期我們介紹了上下文管理器的相關(guān)編程內(nèi)容,諸如何為上下文管理器、上下文管理器協(xié)議、自定義的類(lèi)形式上下文管理器以及函數(shù)型上下文管理器等。相關(guān)內(nèi)容大都配合可實(shí)戰(zhàn)的代碼進(jìn)行了演示和解說(shuō)。要想提高編程技能,多動(dòng)手敲代碼是必不可少的要求。

前言

本文聚焦在Python的上下文管理的講解和應(yīng)用。還是通過(guò)代碼實(shí)例的方式,對(duì)照理解和學(xué)習(xí),以達(dá)到“多快好省”的理解、掌握和應(yīng)用。閑話(huà)少敘,開(kāi)始——

1.何為上下文管理器

上下文管理器是一個(gè)對(duì)象,它定義了在執(zhí)行with語(yǔ)句時(shí)要建立的運(yùn)行時(shí)上下文。上下文管理器是為代碼塊所執(zhí)行的上下文環(huán)境自動(dòng)處理進(jìn)入和退出所需的運(yùn)行時(shí)。上下文管理器通常使用with語(yǔ)句調(diào)用,但也可以通過(guò)直接調(diào)用它們的方法來(lái)使用。

上下文管理器的典型用途包括保存和恢復(fù)各種全局狀態(tài),鎖定和解鎖資源,關(guān)閉打開(kāi)的文件,等等。

在章節(jié)中,我們將學(xué)習(xí)如何使用Python中的上下文管理器以及如何自定義上下文管理器。

1.With語(yǔ)句

with語(yǔ)句用于上下文管理器定義的方法包裝塊的執(zhí)行。這允許封裝常見(jiàn)的try…except…finally使用模式以方便重用。與傳統(tǒng)的try…except…finally塊相比,with語(yǔ)句提供了更短且可重用的代碼。

在Python標(biāo)準(zhǔn)庫(kù)中,許多類(lèi)都支持with語(yǔ)句。一個(gè)非常常見(jiàn)的例子是內(nèi)置的open()函數(shù),它提供了使用with語(yǔ)句處理文件對(duì)象的模式。

下面是with語(yǔ)句的一般語(yǔ)法:

with expression as target:
# 使用target
# 來(lái)處理事情

我們看一個(gè)使用open()函數(shù)的例子。在當(dāng)前項(xiàng)目的files文件夾中有一個(gè)文本文件。文件名為color_names.txt,其中包含一些顏色名稱(chēng)(可自行提供一些文本內(nèi)容)。我們希望通過(guò)使用open()函數(shù)和with語(yǔ)句打開(kāi)并打印該文件中的內(nèi)容。代碼示例如下:

import os
fileDirPath = os.getcwd()+os.sep+"ctxManager"+os.sep #自定義文件路徑
# 指定文件路徑和名稱(chēng)
path = fileDirPath+'files/color_names.txt'

# with 語(yǔ)句
with open(path, mode='r') as file:
# 讀取文件內(nèi)容
print(file.read())

運(yùn)行程序輸出結(jié)果如下

red
orange
yellow
green
blue
white
black

在上面清單中,所看到是with語(yǔ)句的一個(gè)常見(jiàn)用例。我們使用open()函數(shù)打開(kāi)給定的路徑(path)上的文件,且open()函數(shù)以只讀模式返回文件對(duì)象。然后代碼中使用這個(gè)文件對(duì)象讀取并通過(guò)代碼:print(file.read())將其內(nèi)容打印輸出。

上面示例是上下文管理器的一個(gè)典型用法。為了更好地理解和應(yīng)用上下文管理器,我們還得繼續(xù)往下看。

3. 上下文管理器協(xié)議

上下文管理器協(xié)議(Context Manager Protocol),說(shuō)白了就是上下文管理器的處理機(jī)制,或說(shuō)預(yù)定的規(guī)約標(biāo)準(zhǔn)。這部分內(nèi)容也可查看這里:Python核心協(xié)議。為了閱讀的獨(dú)立性,這里也再說(shuō)一說(shuō)。

Python的with語(yǔ)句支持由上下文管理器定義的運(yùn)行時(shí)上下文的概念。這是通過(guò)一對(duì)方法實(shí)現(xiàn)的,它們?cè)试S用戶(hù)定義的類(lèi)定義運(yùn)行時(shí)上下文,該上下文在語(yǔ)句體執(zhí)行之前進(jìn)入,并在語(yǔ)句結(jié)束時(shí)退出。

前所提到的這些方法稱(chēng)為上下文管理器協(xié)議。來(lái)具體看一下這兩個(gè)方法:

1)__enter__(self)

該方法由with語(yǔ)句調(diào)用,以進(jìn)入與當(dāng)前對(duì)象相關(guān)的運(yùn)行時(shí)上下文。with語(yǔ)句將此方法的返回值綁定到語(yǔ)句的as子句中指定的目標(biāo)(如果有的話(huà))。

上例中返回的上下文管理器的是文件對(duì)象。在背后,文件對(duì)象從__enter__()返回其本身,以允許open()被用作with語(yǔ)句中的上下文表達(dá)式。

2)__exit__(self, exc_type, exc_value, traceback):

當(dāng)執(zhí)行離開(kāi)with代碼塊時(shí)調(diào)用此方法。它退出與此對(duì)象相關(guān)的運(yùn)行時(shí)上下文。參數(shù)描述了導(dǎo)致退出上下文的異常信息。如果沒(méi)有異常而退出上下文,那么所有三個(gè)參數(shù)都將為None。

如果提供了異常,并且希望該方法抑制該異常(即,阻止它被傳播),那么它應(yīng)該返回一個(gè)True值。否則,異常將在退出此方法時(shí)正常處理。__exit__()方法返回一個(gè)布爾值,可以是True或False。

使用上下文管理器協(xié)議中的方法執(zhí)行with語(yǔ)句的過(guò)程如下:

with EXPRESSION as TARGET:
SUITE
  • 計(jì)算上下文表達(dá)式(EXPRESSION)以獲得上下文管理器。
  • 加載上下文管理器的__enter__()以供隨后使用。
  • 加載上下文管理器的__exit__()以供隨后使用。
  •  調(diào)用上下文管理器的__enter__()方法。
  •  如果在with語(yǔ)句中包含了一個(gè)TARGET,則會(huì)將__enter__()的返回值賦給它。
  • 執(zhí)行套件(with語(yǔ)句作用域中的代碼塊)。
  • 調(diào)用上下文管理器的__exit__()方法。如果異常導(dǎo)致套件退出,則其類(lèi)型、值和回溯將作為參數(shù)傳遞給__exit__()。否則,將提供三個(gè)None參數(shù)。

如果套件因異常以外的任何原因退出,則會(huì)忽略__exit__()的返回值,并在所執(zhí)行退出類(lèi)型的正常位置繼續(xù)執(zhí)行后續(xù)代碼(若有)。

4. 類(lèi)形式上下文管理器

現(xiàn)在我們了解了上下文管理器協(xié)議背后的基本思想,讓我們?cè)谝粋€(gè)類(lèi)中實(shí)現(xiàn)它。這個(gè)類(lèi)將是我們的上下文管理器,并稍后在with語(yǔ)句中使用它。

定義的上下文管理器類(lèi)參考示例清單如下:

# 自定義上下文管理器類(lèi)
class CustomContextManager:
# 初始化方法init -> 定義一些變量
def __init__(self, path, mode):
self.path = path
self.mode = mode
self.file = None

# __enter__ method -> open the file
def __enter__(self):
self.file = open(self.path, self.mode)
return self.file

# exit method to close the file

def __exit__(self, exc_type, exc_value,exc_traceback):
self.file.close()

我們的CustomContextManager類(lèi)實(shí)現(xiàn)了成為上下文管理器的必要方法:__enter__和__exit__。

在__init__方法中,它定義了三個(gè)實(shí)例變量來(lái)存儲(chǔ)路徑、模式和文件對(duì)象。

在__enter__方法中,它使用內(nèi)置的open()函數(shù)打開(kāi)指定路徑中的文件。由于open()函數(shù)返回file對(duì)象,我們將其賦值給self.file屬性。

在__exit__方法中,我們將文件關(guān)閉:self.file.close()。

__exit__方法接受三個(gè)參數(shù),它們是上下文管理器協(xié)議所需要的。

現(xiàn)在我們可以在with語(yǔ)句中使用自定義上下文管理器。

使用自定義的類(lèi)上下文管理器的示例(和我們前面的示例雷同):

# 應(yīng)用示例
import os
fileDirPath = os.getcwd()+os.sep+"ctxManager"+os.sep
# 在with語(yǔ)句中使用自定義上下文管理器
file_path = fileDirPath + 'files/color_names.txt'

with CustomContextManager(path=file_path, mode='r') as file:
#輸出文件file內(nèi)容
print(file.read())

運(yùn)行輸出結(jié)果這里不再贅述。簡(jiǎn)單解釋一下代碼。

上面清單中,在with語(yǔ)句中使用CustomContexManager類(lèi),通過(guò)它來(lái)讀取文件內(nèi)容并打印出來(lái)。下面是這個(gè)自定義上下文管理器幕后的故事:

1)在with行,調(diào)用類(lèi)CustomContextManager的方_enter__法

2) __enter__方法打開(kāi)文件并返回它。

3)我們將打開(kāi)的文件簡(jiǎn)單地命名為file。

4)在with語(yǔ)句塊中,讀取文件內(nèi)容并將其打印出來(lái)。

5)with語(yǔ)句自動(dòng)調(diào)用__exit__方法。

6)__exit__方法關(guān)閉文件。

我們?cè)賮?lái)定義另一個(gè)上下文管理器類(lèi)。這次我們想打印指定文件夾中的文件列表。

參考實(shí)現(xiàn)的代碼清單如下:

class ContentList:
'''Prints the content of a directory'''

def __init__(self, directory):
self.directory = directory

def __enter__(self):
return os.listdir(self.directory)

def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is not None:
print("Error getting directory list.")
return True

# 輸出項(xiàng)目目錄下的內(nèi)容
project_directory = '.'
with ContentList(project_directory) as directory_list:
print(directory_list)

在代碼清單中,我們定義了一個(gè)新的上下文管理器。這個(gè)類(lèi)的名字是ContentList。為什么它是一個(gè)上下文管理器?因?yàn)樗鼘?shí)現(xiàn)了上下文管理器協(xié)議(__enter__和__exit__方法)。

我們將目錄路徑作為類(lèi)構(gòu)造函數(shù)__init__方法中的參數(shù)。

在__enter__方法中,只需調(diào)用os模塊中的listdir()方法,就可以獲得該目錄中的內(nèi)容列表:os.listdir(self.directory)。然后返回這個(gè)列表。請(qǐng)注意,在這個(gè)上下文管理器中我們的__enter__方法返回一個(gè)列表。

在__exit__方法中,我們檢查是否存在任何錯(cuò)誤。如果我們的上下文管理器中有錯(cuò)誤,exc_type、exc_val、exc_tb參數(shù)值將不會(huì)為None。因此,我們檢查exc_type是否為None以打印錯(cuò)誤文本。

在with語(yǔ)句中使用該上下文管理器。由于它返回一個(gè)列表對(duì)象,我們只需將返回值賦值給directory_list變量。在with語(yǔ)句的主體中,我們打印這個(gè)列表。運(yùn)行程序后在輸出中,可以看到項(xiàng)目目錄中的內(nèi)容列表。記住,"."表示當(dāng)前目錄,在我們的例子中是項(xiàng)目根目錄(由于項(xiàng)目環(huán)境不同,輸出內(nèi)容可能也不一樣)。

6. 函數(shù)形式上下文管理器

前文中,我們學(xué)習(xí)了如何使用類(lèi)語(yǔ)法定義上下文管理器。但是有點(diǎn)繁瑣和冗長(zhǎng)。因?yàn)樾枰鞔_地實(shí)現(xiàn)__enter__和exit__方法,還需要處理可能的異常。所以希望Python中能有在創(chuàng)建上下文管理器更好的方法:基于函數(shù)的上下文管理器。

其實(shí)函數(shù)上下文管理器是使用生成器和contextlib.contextmanager裝飾器的特殊函數(shù)。 contextlib.contextmanager裝飾器負(fù)責(zé)實(shí)現(xiàn)上下文管理器協(xié)議。

下面就來(lái)定義一個(gè)函數(shù)型上下文管理器。

from contextlib import contextmanager

# 定義上下文管理器函數(shù)
@contextmanager
def function_based_context_manager():
print("進(jìn)入上下文: __enter__")
yield "這是個(gè)基于上下文管理器的函數(shù)"
print("離開(kāi)上下文: __exit__")

# with語(yǔ)句中使用上下文管理器函數(shù)
with function_based_context_manager() as yield_text:
print(yield_text)

運(yùn)行程序輸出結(jié)果類(lèi)似如下:

進(jìn)入上下文: __enter__
這是個(gè)基于上下文管理器的函數(shù)
離開(kāi)上下文: __exit__

在上面代碼中,我們定義了一個(gè)作為上下文管理器的自定義函數(shù)。contextmanager裝飾器將常規(guī)函數(shù)轉(zhuǎn)換為全堆棧上下文管理器(自動(dòng)實(shí)現(xiàn)上下文管理器的協(xié)議)。如果你為函數(shù)提供了@contextmanager裝飾器,就不需要擔(dān)心實(shí)現(xiàn)__enter__和__exit__函數(shù)。

代碼中的yield語(yǔ)句在基于類(lèi)的上下文管理器中的__enter__方法中充當(dāng)返回語(yǔ)句。由于我們使用了yield語(yǔ)句,故此,這個(gè)基于函數(shù)的上下文管理器也是生成器函數(shù)。

再來(lái)定義一個(gè)新的上下文管理器。這一次,它將以寫(xiě)的模式打開(kāi)一個(gè)文件并添加一些文本。示例如下:

代碼清單

在清單中,我們定義了一個(gè)基于函數(shù)的上下文管理器。在try塊中,它嘗試打開(kāi)指定路徑中的文件,并指定了文件的默認(rèn)編碼集。如果它成功地打開(kāi)它,那么它將生成(返回)file_object。在finally塊中,我們檢查是否有一個(gè)file_object要關(guān)閉。如果file_object不是None,則關(guān)閉file_object。

在with語(yǔ)句中,我們用文件名funBasedContextManagers.txt調(diào)用上下文管理器。上下文管理器以寫(xiě)模式打開(kāi)該文件并返回文件對(duì)象,我們將其簡(jiǎn)單命名為file。接著在這個(gè)文件中寫(xiě)入一些文本。記住,如果這樣的文件不存在,'w'模式將創(chuàng)建一個(gè)空文件。

運(yùn)行上面程序,若文件不存在,則生成相應(yīng)名稱(chēng)的文件并保持寫(xiě)入的內(nèi)容。若文件存在,則這種寫(xiě)入文件是每次情況源文件再寫(xiě)入內(nèi)容的,這一點(diǎn)操作請(qǐng)注意。

像這種處理“收尾”工作的,使用上下文管理器特別方便,尤其涉及到數(shù)據(jù)庫(kù)操作方面,比如可以自己包裝一個(gè)來(lái)完成自動(dòng)的關(guān)閉連接等。

本文小結(jié)

本期我們介紹了上下文管理器的相關(guān)編程內(nèi)容,諸如何為上下文管理器、上下文管理器協(xié)議、自定義的類(lèi)形式上下文管理器以及函數(shù)型上下文管理器等。相關(guān)內(nèi)容大都配合可實(shí)戰(zhàn)的代碼進(jìn)行了演示和解說(shuō)。要想提高編程技能,多動(dòng)手敲代碼是必不可少的要求。

責(zé)任編輯:武曉燕 來(lái)源: 今日頭條
相關(guān)推薦

2025-06-06 08:00:00

上下文管理器Python開(kāi)發(fā)

2014-04-04 10:27:00

Python上下文管理器

2022-06-29 14:15:01

Python計(jì)時(shí)器上下文管理器

2022-10-28 16:24:33

Context上下文鴻蒙

2023-11-16 08:46:27

上下文管理器Python

2024-11-14 09:00:00

Python上下文管理器

2025-07-08 08:34:04

2023-12-10 13:37:23

Python編程上下文管理

2025-09-09 09:49:36

2017-05-11 14:00:02

Flask請(qǐng)求上下文應(yīng)用上下文

2021-01-26 05:19:56

語(yǔ)言Go Context

2025-08-28 06:05:00

2012-12-31 10:01:34

SELinuxSELinux安全

2025-10-14 01:55:00

AI應(yīng)用上下文工程機(jī)器人

2022-09-14 13:13:51

JavaScript上下文

2025-02-08 09:13:40

2021-11-03 16:41:30

Windows 11操作系統(tǒng)微軟

2022-09-15 08:01:14

繼承基礎(chǔ)設(shè)施基礎(chǔ)服務(wù)

2025-05-09 09:15:00

2023-07-11 10:02:23

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)