簡(jiǎn)介
????????上下文管理屬于流程控制特性中一部分张症,在python中仓技,上下文管理語(yǔ)法主要是使用with關(guān)鍵詞。with語(yǔ)句會(huì)設(shè)置一個(gè)臨時(shí)的上下文俗他,對(duì)對(duì)象進(jìn)行控制脖捻,并且清除上下文,這樣做的好處是能夠減少錯(cuò)誤兆衅,使得代碼整潔易讀地沮。我們?cè)敿?xì)分析下流程控制的else,和上下文管理羡亩。
else字句
????????當(dāng)然摩疑,else是我們經(jīng)常用的關(guān)鍵詞,相信大家大部分都是使用于if-else對(duì)畏铆。其實(shí)在python中雷袋,還有其他情況能使用else字句,當(dāng)然都屬于流程控制的范濤辞居。如for/else楷怒、while/else 和 try/else。
- for/else對(duì)中else瓦灶,當(dāng)且僅當(dāng)for循環(huán)運(yùn)行完畢時(shí)鸠删,也就是所有元素都遍歷,不能中斷贼陶,else才會(huì)執(zhí)行
for i in range(10):
pass
else:
print("---else----")
輸出結(jié)果:
---else----
當(dāng)for循環(huán)中有break時(shí)刃泡,else字句不會(huì)執(zhí)行:
for i in range(10):
if i == 7:
break
else:
print("---else----")
- while/else句子中,當(dāng)while循環(huán)因條件不滿足而退出循環(huán)時(shí)碉怔,也就是沒(méi)有break中斷捅僵,else會(huì)被執(zhí)行:
flag = 5
while flag:
flag -= 1
else:
print("---else----")
輸出結(jié)果:
---else----
- try/else,當(dāng)try語(yǔ)句沒(méi)有拋出異常時(shí),會(huì)執(zhí)行else字句眨层。
其實(shí)else在上述語(yǔ)句中不是很常用庙楚,但是也是有些情況使用會(huì)很方便的,例如:
for i in range(10):
if i == 12:
break
else:
print("列表中沒(méi)有12")
上述情況下趴樱,使用else之后馒闷,無(wú)需設(shè)置控制標(biāo)志或者額外的if語(yǔ)句酪捡,如果不使用else∧烧耍恐怕要像下面這種寫法了:
flag = 0
for i in range(10):
if i == 12:
flag = 1
break
if flag:
pass
else:
print("列表中沒(méi)有12")
可見逛薇,有些時(shí)候在for循環(huán)使用else,也能省去很多麻煩的疏虫。
with語(yǔ)句
????????上下文管理器對(duì)象存在的目的是管理with語(yǔ)句永罚,with語(yǔ)句的目的是簡(jiǎn)化try/finally 模式。用于保證一段代碼執(zhí)行后進(jìn)行某些操作卧秘,即使拋出異常也會(huì)執(zhí)行收尾工作呢袱。
????????上下文管理器主要包含兩個(gè)特殊方法,__enter__
和__exit__
,with開始時(shí)翅敌,會(huì)調(diào)用上下文管理器對(duì)象的__enter__
方法羞福,with結(jié)束后,會(huì)調(diào)用__exit__
方法蚯涮。
????????最常見的with語(yǔ)句是文件打開治专,確保最后文件能夠關(guān)閉:
with open("test.txt") as f:
pass
f綁定到打開的文件上面,是調(diào)用上下文管理器對(duì)象的__enter__
方法的結(jié)果遭顶。無(wú)論這個(gè)流程語(yǔ)句以何種情況結(jié)束张峰,最后都會(huì)調(diào)用__exit__
方法。
如下棒旗,定義一個(gè)簡(jiǎn)單的上下文管理器對(duì)象:
class Test(object):
def __enter__(self):
print("enter")
def __exit__(self, exc_type, exc_value, traceback):
print("exit")
print(exc_type, exc_value, traceback)
with Test():
pass
輸出結(jié)果:
enter
exit
None None None
若有異常:
class Test(object):
def __enter__(self):
print("enter")
def __exit__(self, exc_type, exc_value, traceback):
print("exit",exc_type, exc_value, traceback,"exit")
with Test():
a
輸出結(jié)果:
enter
exit <class 'NameError'> name 'a' is not defined <traceback object at 0x000001A421F68708> exit
Traceback (most recent call last):
File "c:/Users/DELL/Desktop/ssj/search/descrip.py", line 12, in <module>
a
NameError: name 'a' is not defined
調(diào)用方法__enter__
時(shí)挟炬,除了self,不會(huì)傳其他參數(shù)的嗦哆。
調(diào)用__exit__
方法時(shí):
沒(méi)有異常發(fā)生時(shí)谤祖,除了self,傳的三個(gè)參數(shù)都是None老速;
有異常情況時(shí)粥喜,三個(gè)參數(shù)的意義:
exc_type:異常類
exc_value:異常消息
traceback:traceback對(duì)象。
上下文管理器標(biāo)準(zhǔn)庫(kù)中也有很多用法:
比如django數(shù)據(jù)庫(kù)中的事務(wù):
with transaction.atomic():
pass
threading 多線程中的鎖:
whit threading.Lock():
pass
????????其實(shí)關(guān)于上下文管理器橘券,有一個(gè)專門的內(nèi)置庫(kù)contextlib
這個(gè)模塊提供了一個(gè)很實(shí)用的工具@contextmanager额湘,這個(gè)裝飾器能把生成器函數(shù)變成上下文管理器,
from contextlib import contextmanager
@contextmanager
def test():
print("enter")
yield "aaaa"
print("exit")
with test() as f:
pass
print(f)
輸出結(jié)果:
enter
exit
aaaa
在使用@contextmanager裝飾的生成器中旁舰,yield語(yǔ)句把上下分成兩個(gè)部分锋华,yield以上,是在with執(zhí)行時(shí)箭窜,也就是調(diào)用方法__enter__
時(shí)毯焕,yield下面的代碼在調(diào)用__exit__
方法時(shí)執(zhí)行。