Python是一門優(yōu)雅而簡(jiǎn)潔的編程語(yǔ)言,它提供了許多高級(jí)特性,讓我們的編程更加方便和高效。其中一個(gè)特性就是with語(yǔ)句,它可以讓我們?cè)谔幚硪恍┬枰蜷_和關(guān)閉資源的操作時(shí),不用擔(dān)心忘記關(guān)閉資源或者出現(xiàn)異常。在本文中,我將介紹一下with語(yǔ)句的用法和用途,以及它在Python 3.6中新增的一些功能。
with語(yǔ)句的基本用法
with語(yǔ)句的基本語(yǔ)法是這樣的:
with expression as variable:
# do something with variable
expression是一個(gè)表達(dá)式,它會(huì)返回一個(gè)上下文管理器(context manager),這是一個(gè)實(shí)現(xiàn)了__enter__
和__exit__
方法的對(duì)象。variable是一個(gè)變量,它會(huì)接收__enter__
方法返回的值。當(dāng)進(jìn)入with語(yǔ)句時(shí),會(huì)調(diào)用上下文管理器的__enter__
方法,并將返回值賦給variable。當(dāng)離開with語(yǔ)句時(shí),會(huì)調(diào)用上下文管理器的__exit__
方法,并傳入異常信息(如果有的話)。
with語(yǔ)句的作用是讓我們可以在執(zhí)行一些操作之前和之后,自動(dòng)執(zhí)行一些清理或者釋放資源的操作。比如,當(dāng)我們要打開一個(gè)文件并讀取內(nèi)容時(shí),我們通常要這樣寫:
f = open('test.txt', 'r')
content = f.read()
f.close()
這樣寫有兩個(gè)問(wèn)題:一是如果讀取文件過(guò)程中出現(xiàn)異常,可能導(dǎo)致文件沒(méi)有關(guān)閉;二是每次都要寫f.close()很麻煩。如果我們用with語(yǔ)句,就可以簡(jiǎn)化為:
with open('test.txt', 'r') as f:
content = f.read()
這樣寫的好處是:一是不管讀取文件過(guò)程中是否出現(xiàn)異常,都會(huì)自動(dòng)關(guān)閉文件;二是代碼更加簡(jiǎn)潔和清晰。這是因?yàn)閛pen函數(shù)返回的是一個(gè)文件對(duì)象,它實(shí)現(xiàn)了上下文管理器協(xié)議,所以可以用在with語(yǔ)句中。
with語(yǔ)句的進(jìn)階用法
除了可以用在內(nèi)置的上下文管理器對(duì)象上,我們也可以自己定義上下文管理器類,并用在with語(yǔ)句中。比如,我們想要實(shí)現(xiàn)一個(gè)計(jì)時(shí)器類,它可以在進(jìn)入和離開某個(gè)代碼塊時(shí),打印出執(zhí)行時(shí)間。我們可以這樣寫:
import time
class Timer:
def __enter__(self):
self.start = time.time()
return self
def __exit__(self, exc_type, exc_value, exc_traceback):
self.end = time.time()
print(f'Elapsed time: {self.end - self.start} seconds')
然后我們就可以這樣使用:
with Timer() as t:
# do some heavy computation
time.sleep(3)
輸出:
Elapsed time: 3.000213861465454 seconds
在Python 3.6中,with語(yǔ)句還增加了一些新功能。比如,我們可以在一個(gè)with語(yǔ)句中使用多個(gè)上下文管理器,只要用逗號(hào)分隔即可。比如:
with open('test.txt', 'r') as f1, open('test_copy.txt', 'w') as f2:
# copy content from f1 to f2
這樣就可以同時(shí)打開兩個(gè)文件,并在離開時(shí)自動(dòng)關(guān)閉。
另外,我們還可以使用async with語(yǔ)句,在異步編程中使用異步上下文管理器。異步上下文管理器是實(shí)現(xiàn)了__aenter__
和__aexit__
方法的對(duì)象,它們可以在協(xié)程中使用,并且支持await語(yǔ)法。比如:
import aiohttp
import asyncio
async def fetch(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
async def main():
html = await fetch('https://www.python.org')
print(html)
asyncio.run(main())
這樣就可以使用aiohttp庫(kù),異步地獲取網(wǎng)頁(yè)內(nèi)容,并在離開時(shí)自動(dòng)關(guān)閉會(huì)話和響應(yīng)。
總結(jié)
with語(yǔ)句是Python中一個(gè)非常有用的特性,它可以讓我們?cè)谔幚硪恍┬枰蜷_和關(guān)閉資源的操作時(shí),不用擔(dān)心忘記關(guān)閉資源或者出現(xiàn)異常。它還可以讓我們的代碼更加簡(jiǎn)潔和清晰。在Python 3.6中,with語(yǔ)句還增加了一些新功能,讓我們可以在一個(gè)with語(yǔ)句中使用多個(gè)上下文管理器,或者在異步編程中使用異步上下文管理器。如果你還沒(méi)有使用過(guò)with語(yǔ)句,那么我建議你嘗試一下,你會(huì)發(fā)現(xiàn)它的魅力的。
python相關(guān)課程推薦:python相關(guān)課程