摘要:項目地址引入了語句與上下文管理器類型,其主要作用包括保存重置各種全局狀態,鎖住或解鎖資源,關閉打開的文件等。了解了語句的執行過程,我們可以編寫自己的上下文管理器。生成器的寫法更簡潔,適合快速生成一個簡單的上下文管理器。
項目地址:https://git.io/pytips
Python 2.5 引入了 with 語句(PEP 343)與上下文管理器類型(Context Manager Types),其主要作用包括:
保存、重置各種全局狀態,鎖住或解鎖資源,關閉打開的文件等。With Statement Context Managers
一種最普遍的用法是對文件的操作:
with open("utf8.txt", "r") as f: print(f.read())
你好,世界!
上面的例子也可以用 try...finally... 實現,它們的效果是相同(或者說上下文管理器就是封裝、簡化了錯誤捕捉的過程):
try: f = open("utf8.txt", "r") print(f.read()) finally: f.close()
你好,世界!
除了文件對象之外,我們也可以自己創建上下文管理器,與 0x01 中介紹的迭代器類似,只要定義了 __enter__() 和 __exit__() 方法就成為了上下文管理器類型。with 語句的執行過程如下:
執行 with 后的語句獲取上下文管理器,例如 open("utf8.txt", "r") 就是返回一個 file object;
加載 __exit__() 方法備用;
執行 __enter__(),該方法的返回值將傳遞給 as 后的變量(如果有的話);
執行 with 語法塊的子句;
執行 __exit__() 方法,如果 with 語法塊子句中出現異常,將會傳遞 type, value, traceback 給 __exit__(),否則將默認為 None;如果 __exit__() 方法返回 False,將會拋出異常給外層處理;如果返回 True,則忽略異常。
了解了 with 語句的執行過程,我們可以編寫自己的上下文管理器。假設我們需要一個引用計數器,而出于某些特殊的原因需要多個計數器共享全局狀態并且可以相互影響,而且在計數器使用完畢之后需要恢復初始的全局狀態:
_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 加入了多個并列上下文管理器 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}
上面的例子很別扭但是可以很好地說明 with 語句的執行順序,只是每次定義兩個方法看起來并不是很簡潔,一如既往地,Python 提供了 @contextlib.contextmanager + generator 的方式來簡化這一過程(正如 0x01 中 yield 簡化迭代器一樣):
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}
這里對生成器的要求是必須只能返回一個值(只有一次 yield),返回的值相當于 __enter__() 的返回值;而 yield 后的語句相當于 __exit__()。
生成器的寫法更簡潔,適合快速生成一個簡單的上下文管理器。
除了上面兩種方式,Python 3.2 中新增了 contextlib.ContextDecorator,可以允許我們自己在 class 層面定義新的”上下文管理修飾器“,有興趣可以到官方文檔查看。至少在我目前看來好像并沒有帶來更多方便(除了可以省掉一層縮進之外:()。
上下文管理器的概念與修飾器有很多相似之處,但是要記住的是 with 語句的目的是為了更優雅地收拾殘局而不是替代 try...finally...,畢竟在 The Zen of Python 中,
Explicit is better than implicit.
比
Simple is better than complex.
更重要:P。
歡迎關注公眾號 PyHub!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/37820.html
項目地址:https://git.io/pytips Python 的修飾器是一種語法糖(Syntactic Sugar),也就是說: @decorator @wrap def func(): pass 是下面語法的一種簡寫: def func(): pass func = decorator(wrap(func)) 關于修飾器的兩個主要問題: 修飾器用來修飾誰 誰可以作為修飾器...
摘要:中關于線程的標準庫是,之前在版本中的在之后更名為,無論是還是都應該盡量避免使用較為底層的而應該使用。而與線程相比,協程尤其是結合事件循環無論在編程模型還是語法上,看起來都是非常友好的單線程同步過程。 項目地址:https://git.io/pytips 要說到線程(Thread)與協程(Coroutine)似乎總是需要從并行(Parallelism)與并發(Concurrency)談起...
摘要:項目地址迭代器與生成器迭代器與生成器是中比較常用又很容易混淆的兩個概念,今天就把它們梳理一遍,并舉一些常用的例子。生成器前面說到創建迭代器有種方法,其中第三種就是生成器。 項目地址:https://git.io/pytips 迭代器與生成器 迭代器(iterator)與生成器(generator)是 Python 中比較常用又很容易混淆的兩個概念,今天就把它們梳理一遍,并舉一些常用的例...
摘要:借鑒了中的某些迭代器的構造方法,并在中實現該模塊是通過實現,源代碼。 項目地址:https://git.io/pytips 0x01 介紹了迭代器的概念,即定義了 __iter__() 和 __next__() 方法的對象,或者通過 yield 簡化定義的可迭代對象,而在一些函數式編程語言(見 0x02 Python 中的函數式編程)中,類似的迭代器常被用于產生特定格式的列表(或序列)...
摘要:項目地址閉包在計算機科學中,閉包英語,又稱詞法閉包或函數閉包,是引用了自由變量的函數。這個被引用的自由變量將和這個函數一同存在,即使已經離開了創造它的環境也不例外。 項目地址:https://git.io/pytips 閉包(Closure) 在計算機科學中,閉包(英語:Closure),又稱詞法閉包(Lexical Closure)或函數閉包(function closures),是...
閱讀 2624·2021-11-18 10:07
閱讀 1083·2021-08-03 14:04
閱讀 726·2019-08-30 13:08
閱讀 2579·2019-08-29 15:33
閱讀 1087·2019-08-29 14:07
閱讀 2985·2019-08-29 14:04
閱讀 1435·2019-08-29 11:19
閱讀 1144·2019-08-29 10:59