摘要:項(xiàng)目地址引入了語(yǔ)句與上下文管理器類型,其主要作用包括保存重置各種全局狀態(tài),鎖住或解鎖資源,關(guān)閉打開(kāi)的文件等。了解了語(yǔ)句的執(zhí)行過(guò)程,我們可以編寫(xiě)自己的上下文管理器。生成器的寫(xiě)法更簡(jiǎn)潔,適合快速生成一個(gè)簡(jiǎn)單的上下文管理器。
項(xiàng)目地址:https://git.io/pytips
Python 2.5 引入了 with 語(yǔ)句(PEP 343)與上下文管理器類型(Context Manager Types),其主要作用包括:
保存、重置各種全局狀態(tài),鎖住或解鎖資源,關(guān)閉打開(kāi)的文件等。With Statement Context Managers
一種最普遍的用法是對(duì)文件的操作:
with open("utf8.txt", "r") as f: print(f.read())
你好,世界!
上面的例子也可以用 try...finally... 實(shí)現(xiàn),它們的效果是相同(或者說(shuō)上下文管理器就是封裝、簡(jiǎn)化了錯(cuò)誤捕捉的過(guò)程):
try: f = open("utf8.txt", "r") print(f.read()) finally: f.close()
你好,世界!
除了文件對(duì)象之外,我們也可以自己創(chuàng)建上下文管理器,與 0x01 中介紹的迭代器類似,只要定義了 __enter__() 和 __exit__() 方法就成為了上下文管理器類型。with 語(yǔ)句的執(zhí)行過(guò)程如下:
執(zhí)行 with 后的語(yǔ)句獲取上下文管理器,例如 open("utf8.txt", "r") 就是返回一個(gè) file object;
加載 __exit__() 方法備用;
執(zhí)行 __enter__(),該方法的返回值將傳遞給 as 后的變量(如果有的話);
執(zhí)行 with 語(yǔ)法塊的子句;
執(zhí)行 __exit__() 方法,如果 with 語(yǔ)法塊子句中出現(xiàn)異常,將會(huì)傳遞 type, value, traceback 給 __exit__(),否則將默認(rèn)為 None;如果 __exit__() 方法返回 False,將會(huì)拋出異常給外層處理;如果返回 True,則忽略異常。
了解了 with 語(yǔ)句的執(zhí)行過(guò)程,我們可以編寫(xiě)自己的上下文管理器。假設(shè)我們需要一個(gè)引用計(jì)數(shù)器,而出于某些特殊的原因需要多個(gè)計(jì)數(shù)器共享全局狀態(tài)并且可以相互影響,而且在計(jì)數(shù)器使用完畢之后需要恢復(fù)初始的全局狀態(tài):
_G = {"counter": 99, "user": "admin"} class Refs(): def __init__(self, name = None): self.name = name self._G = _G self.init = self._G["counter"] def __enter__(self): return self def __exit__(self, *args): self._G["counter"] = self.init return False def acc(self, n = 1): self._G["counter"] += n def dec(self, n = 1): self._G["counter"] -= n def __str__(self): return "COUNTER #{name}: {counter}".format(**self._G, name=self.name) with Refs("ref1") as ref1, Refs("ref2") as ref2: # Python 3.1 加入了多個(gè)并列上下文管理器 for _ in range(3): ref1.dec() print(ref1) ref2.acc(2) print(ref2) print(_G)
COUNTER #ref1: 98 COUNTER #ref2: 100 COUNTER #ref1: 99 COUNTER #ref2: 101 COUNTER #ref1: 100 COUNTER #ref2: 102 {"user": "admin", "counter": 99}
上面的例子很別扭但是可以很好地說(shuō)明 with 語(yǔ)句的執(zhí)行順序,只是每次定義兩個(gè)方法看起來(lái)并不是很簡(jiǎn)潔,一如既往地,Python 提供了 @contextlib.contextmanager + generator 的方式來(lái)簡(jiǎn)化這一過(guò)程(正如 0x01 中 yield 簡(jiǎn)化迭代器一樣):
from contextlib import contextmanager as cm _G = {"counter": 99, "user": "admin"} @cm def ref(): counter = _G["counter"] yield _G _G["counter"] = counter with ref() as r1, ref() as r2: for _ in range(3): r1["counter"] -= 1 print("COUNTER #ref1: {}".format(_G["counter"])) r2["counter"] += 2 print("COUNTER #ref2: {}".format(_G["counter"])) print("*"*20) print(_G)
COUNTER #ref1: 98 COUNTER #ref2: 100 COUNTER #ref1: 99 COUNTER #ref2: 101 COUNTER #ref1: 100 COUNTER #ref2: 102 ******************** {"user": "admin", "counter": 99}
這里對(duì)生成器的要求是必須只能返回一個(gè)值(只有一次 yield),返回的值相當(dāng)于 __enter__() 的返回值;而 yield 后的語(yǔ)句相當(dāng)于 __exit__()。
生成器的寫(xiě)法更簡(jiǎn)潔,適合快速生成一個(gè)簡(jiǎn)單的上下文管理器。
除了上面兩種方式,Python 3.2 中新增了 contextlib.ContextDecorator,可以允許我們自己在 class 層面定義新的”上下文管理修飾器“,有興趣可以到官方文檔查看。至少在我目前看來(lái)好像并沒(méi)有帶來(lái)更多方便(除了可以省掉一層縮進(jìn)之外:()。
上下文管理器的概念與修飾器有很多相似之處,但是要記住的是 with 語(yǔ)句的目的是為了更優(yōu)雅地收拾殘局而不是替代 try...finally...,畢竟在 The Zen of Python 中,
Explicit is better than implicit.
比
Simple is better than complex.
更重要:P。
歡迎關(guān)注公眾號(hào) PyHub!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/37820.html
項(xiàng)目地址:https://git.io/pytips Python 的修飾器是一種語(yǔ)法糖(Syntactic Sugar),也就是說(shuō): @decorator @wrap def func(): pass 是下面語(yǔ)法的一種簡(jiǎn)寫(xiě): def func(): pass func = decorator(wrap(func)) 關(guān)于修飾器的兩個(gè)主要問(wèn)題: 修飾器用來(lái)修飾誰(shuí) 誰(shuí)可以作為修飾器...
摘要:中關(guān)于線程的標(biāo)準(zhǔn)庫(kù)是,之前在版本中的在之后更名為,無(wú)論是還是都應(yīng)該盡量避免使用較為底層的而應(yīng)該使用。而與線程相比,協(xié)程尤其是結(jié)合事件循環(huán)無(wú)論在編程模型還是語(yǔ)法上,看起來(lái)都是非常友好的單線程同步過(guò)程。 項(xiàng)目地址:https://git.io/pytips 要說(shuō)到線程(Thread)與協(xié)程(Coroutine)似乎總是需要從并行(Parallelism)與并發(fā)(Concurrency)談起...
摘要:項(xiàng)目地址迭代器與生成器迭代器與生成器是中比較常用又很容易混淆的兩個(gè)概念,今天就把它們梳理一遍,并舉一些常用的例子。生成器前面說(shuō)到創(chuàng)建迭代器有種方法,其中第三種就是生成器。 項(xiàng)目地址:https://git.io/pytips 迭代器與生成器 迭代器(iterator)與生成器(generator)是 Python 中比較常用又很容易混淆的兩個(gè)概念,今天就把它們梳理一遍,并舉一些常用的例...
摘要:借鑒了中的某些迭代器的構(gòu)造方法,并在中實(shí)現(xiàn)該模塊是通過(guò)實(shí)現(xiàn),源代碼。 項(xiàng)目地址:https://git.io/pytips 0x01 介紹了迭代器的概念,即定義了 __iter__() 和 __next__() 方法的對(duì)象,或者通過(guò) yield 簡(jiǎn)化定義的可迭代對(duì)象,而在一些函數(shù)式編程語(yǔ)言(見(jiàn) 0x02 Python 中的函數(shù)式編程)中,類似的迭代器常被用于產(chǎn)生特定格式的列表(或序列)...
摘要:項(xiàng)目地址閉包在計(jì)算機(jī)科學(xué)中,閉包英語(yǔ),又稱詞法閉包或函數(shù)閉包,是引用了自由變量的函數(shù)。這個(gè)被引用的自由變量將和這個(gè)函數(shù)一同存在,即使已經(jīng)離開(kāi)了創(chuàng)造它的環(huán)境也不例外。 項(xiàng)目地址:https://git.io/pytips 閉包(Closure) 在計(jì)算機(jī)科學(xué)中,閉包(英語(yǔ):Closure),又稱詞法閉包(Lexical Closure)或函數(shù)閉包(function closures),是...
閱讀 2641·2021-11-18 10:07
閱讀 1090·2021-08-03 14:04
閱讀 733·2019-08-30 13:08
閱讀 2587·2019-08-29 15:33
閱讀 1102·2019-08-29 14:07
閱讀 3002·2019-08-29 14:04
閱讀 1448·2019-08-29 11:19
閱讀 1155·2019-08-29 10:59