python contextlib 上下文管理器

來源:互聯網
上載者:User

標籤:log   對象   lock   enter   font   already   返回   ace   err   

 

1、with操作符

在python中讀寫檔案,可能需要這樣的代碼

try-finally讀寫檔案

file_text = Nonetry:    file_text = open(‘./text‘, ‘r‘)    print file_text.read()except IOError, ex:    traceback.print_exc()finally:    if file_text:        file_text.close()

同樣,在python中使用線程鎖,可能需要這樣的代碼

try-finally線程鎖

lock = threading.Lock()lock.acquire()try:    passexcept Exception, ex:    traceback.print_exc()finally:    lock.release()

可能你會覺得這種寫法很不方便,python提供了with操作符,你可以這樣操作

with讀寫檔案

with open(‘./text‘, ‘r‘) as file_text:    print file_text.read()

with線程鎖

with lock:    pass

是不是方便多了。

其實,不只是lock和file可以使用with操作符。

實際上,任何對象,只要正確實現上下文管理,就可以使用with語句。實現上下文管理是通過 __enter__ 和 __exit__ 這兩個方法實現的。

 

2、上下文管理

上下文管理可以為我們屏蔽內容相關的複雜性。例如,我們實現一個類Cat,實現其__enter__和__exit__方法。

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

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

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

如下。

class Cat(object):    def __init__(self, name):        self.name = name    def __enter__(self):        print ‘enter from Cat named %s‘ % self.name        return self    def hello(self):        print ‘hello, %s‘ % self.name    def __exit__(self, exc_type, exc_val, exc_tb):        print ‘exit from Cat named %s‘ % self.name

執行,並列印結果

with Cat(‘Tom‘) as tom:    tom.hello()enter from Cat named Tomhello, Tomexit from Cat named Tom

這裡我們執行as tom獲得了Cat類的一個執行個體,這是通過__enter__方法的返回得到的。

當然,我們可以管理多個,請注意進入和退出的順序。

with Cat(‘Tom‘) as tom, Cat(‘Harry‘) as harry:    tom.hello()    harry.hello()enter from Cat named Tomenter from Cat named Harryhello, Tomhello, Harryexit from Cat named Harryexit from Cat named Tom

 

3、contextmanager

可能你還是覺得實現__enter__和__exit__很麻煩。python提供了contextlib.contextmanager

讓我們重寫上面的例子,使用contextmanager

from contextlib import contextmanager as _contextmanager@_contextmanagerdef cat(name):    print ‘enter cat named %s‘ % name    yield name    print ‘exit cat named %s‘ % name

執行,並列印結果

with cat(‘Kitty‘) as kitty:    print ‘hello, %s‘ % kittyenter cat named Kittyhello, Kittyexit cat named Kitty

as後面的執行個體,是通過yield語句返回的。這裡是返回了一個字串。

當然,同樣支援管理多個執行個體

with cat(‘Kitty‘) as kitty, cat(‘Tom‘) as tom:    print ‘hello, %s‘ % kitty    print ‘hello, %s‘ % tomenter cat named Kittyenter cat named Tomhello, Kittyhello, Tomexit cat named Tomexit cat named Kitty

 

4、最後給出一個執行個體

使用上線文管理器實現redis分布式鎖

import redisimport timeimport threadingimport tracebackfrom contextlib import contextmanager as _contextmanagerr = redis.Redis(host=‘localhost‘, port=6379, db=0)@_contextmanagerdef dist_lock(client, key):    dist_lock_key = ‘lock:%s‘ % key    try:        _acquire_lock(client, dist_lock_key)        yield        _release_lock(client, dist_lock_key)    except Exception, ex:        passdef _acquire_lock(client, key):    is_lock = r.set(key, 1, nx=True, ex=10)    if not is_lock:        raise Exception("already locked!")def _release_lock(client, key):    client.delete(key)def func():    while 1:        try:            with dist_lock(r, "key"):                print "*"                time.sleep(8)        except Exception, ex:            passthread_list = list()for i in range(10):    thread_list.append(threading.Thread(target=func))for thread in thread_list:    thread.start()for thread in thread_list:    thread.join()

 

python contextlib 上下文管理器

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.