国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

python上下文管理器及with語句

2019-11-14 17:41:59
字體:
來源:轉載
供稿:網友

with語句支持在一個叫上下文管理器的對象的控制下執行一系列語句,語法大概如下:

with context as var:    statements

其中的context必須是個上下文管理器,它實現了兩個方法__enter__,__exit__。

1.需求是怎么產生的

在正常的管理各種系統資源(文件、鎖定和連接),在涉及到異常時通常是個棘手的問題。異常很可能導致控制流跳過負責釋放關鍵資源的語句。

看一段簡單的文件寫入代碼:

filename = 'my_file.txt' f = open(filename,'w')  f.write('Hello ')  f.write('World')  f.close() 

如果發生了意外的情況,例如寫入'World'時磁盤空間不足,就會拋出異常,那么close()語句將不會被執行。

一般的解決方案是使用try-finally語句:

try:    filename = 'my_file.txt'     f = open(filename,'w')      f.write('Hello ')      f.write('World')finally:    f.close() 

但隨著語句的增多,try-finally顯然不夠簡潔,用with-as語句可以很簡潔的實現以上功能:

with open('my_file','w') as f:    f.write('Hello ')    f.write('World')

這樣不僅能處理出現異常的情況,而且還避免了在open一個文件后忘記了寫close()方法的情況。

線程中的鎖其實也實現了上下文管理協議:

import threadingwith threading.Lock():    # 關鍵部分      statements    # 關鍵部分結束

再也不怕忘記將鎖釋放了。

2.上下文管理器的實現

上下文管理器要實現__enter__和__exit__的特殊方法。

__enter__(self): 進入上下文管理器時調用此方法,其返回值將被放入with-as語句中as說明符指定的變量中。

__exit__(self,type,value,tb):離開上下文管理器調用此方法。如果有異常出現,type、value、tb分別為異常的類型、值和追蹤信息。如果沒有異常,

3個參數均設為None。此方法返回值為True或者False,分別指示被引發的異常得到了還是沒有得到處理。如果返回False,引發的異常會被傳遞出上下文。

文件上下文管理協議大概是如下實現的:

class OpenFile(object):    def __init__(self,filename,mode):        self.filename=filename        self.mode=mode    def __enter__(self):        self.f=open(self.filename,self.mode)        return self.f  #作為as說明符指定的變量的值    def __exit__(self,type,value,tb):        self.f.close()        return False   #異常會被傳遞出上下文with OpenFile('my_file.txt','w') as f:    f.write('Hello ')    f.write('World')

  相當于

try :    執行__enter__的內容finally:    執行__exit__的內容

3.異常的處理 

__exit__函數就能夠拿到關于異常的所有信息(異常類型,異常值以及異常追蹤信息),這些信息將幫助異常處理操作。

class ListTrans(object):    def __init__(self,alist):        self.alist=alist    def __enter__(self):        self.thecopy=list(self.alist)        return self.thecopy    def __exit__(self,exc_type,value,tb):        if exc_type is None:            self.alist[:]=self.thecopy        return False

沒有異常發生時:

alist=[]with ListTrans(alist) as working:    working.append(1)    working.append(2)PRint alist

生成:

[1, 2]

有異常發生時:

alist=[]with ListTrans(alist) as working:    working.append(1)    working.append(2)    raise RuntimeError('we are hosed')print alist

生成:

RuntimeError: we are hosed

alist無變化。

可以捕捉異常:

alist=[]try:    with ListTrans(alist) as working:        working.append(1)        working.append(2)        raise RuntimeError('we are hosed')except RuntimeError as e:    print eprint alist

生成:

we are hosed[]

當然,也可以簡單的將__exit__的返回值設為True來忽略異常。

4.contextmanager裝飾器

@contextmanager

contextlib模塊的contextmanager裝飾器可以更方便的實現上下文管理器。

任何能夠被yield關鍵詞分割成兩部分的函數,都能夠通過裝飾器裝飾的上下文管理器來實現。任何在yield之前的內容都可以看做在代碼塊執行前的操作,

而任何yield之后的操作都可以放在exit函數中。

from contextlib import contextmanager@contextmanagerdef listTrans(alist):    thecopy=list(alist)    yield thecopy    alist[:]=thecopyalist=[]with listTrans(alist) as working:    working.append(1)    working.append(2)print alist

yield返回的值相當于__enter__的返回值。

要注意的是,這不是異常安全的寫法,也就是說,當出現異常時,yield后的語句是不會執行的,想要異常安全,可用try捕捉異常:

from contextlib import contextmanager@contextmanagerdef listTrans(alist):    thecopy=list(alist)    try:        yield thecopy    except RuntimeError:        pass    alist[:]=thecopyalist=[]with listTrans(alist) as working:    working.append(1)    working.append(2)    raise RuntimeError

nested與closing

contextlib模塊還有兩個好玩的方法:nested,closing。

nested:用來更方便的減少嵌套寫法:

當要嵌套的寫上下文管理器時:

with open('toReadFile', 'r') as reader:      with open('toWriteFile', 'w') as writer:          writer.writer(reader.read())

可以用nested簡化寫法:

with contextlib.nested(open('fileToRead.txt', 'r'),                         open('fileToWrite.txt', 'w')) as (reader, writer):      writer.write(reader.read()) 

python2.7后nested就過時了:

with open('fileToRead.txt', 'r') as reader,open('fileToWrite.txt', 'w') as writer:          writer.write(reader.read()) 

closing(object):創建上下文管理器,在執行過程離開with語句時自動執行object.close():

class Door(object) :    def open(self) :        print 'Door is opened'    def close(self) :        print 'Door is closed'with contextlib.closing(Door()) as door :    door.open()

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 内丘县| 双辽市| 名山县| 筠连县| 临邑县| 辽宁省| 宽甸| 瑞昌市| 深州市| 洮南市| 诸暨市| 鸡西市| 桐庐县| 望江县| 奉化市| 喜德县| 五华县| 石门县| 宁乡县| 福安市| 海丰县| 巧家县| 包头市| 韶关市| 淮滨县| 保定市| 武乡县| 南汇区| 邵阳市| 平凉市| 高唐县| 增城市| 科技| 唐海县| 鲜城| 无棣县| 南开区| 宁南县| 盐津县| 乐亭县| 朔州市|