withキーワードから簡単なContextManagerの作成まで(一)

2506 ワード

ここではwith表現を紹介してからwithやアクセサリーなどの知識で自分のContextManagerを実現しようとします
with何ができるの?私の理解はtry except finallyの仕事を簡略化することです.例えば、ファイルオペレータを開いたり、ファイルを読んだり、異常をキャプチャしたり、最後に閉じたりします.この例はwithで最もよく使われる方法で、街中でこの例を見つけることができます.
ファイルopen操作のほかに、実際には他の多くの操作も首を絞めて、中間のキー操作を残しておくことができます.
では、どのように実現すればいいのでしょうか.pythonドキュメントに従って説明します.enter__および_exit__2つの関数でいいです.
簡単:
class ConMgr(object):
    def __init__(self):
        print("__init__ called")
    
    
    def __call__(self, *args):
        print("__call__ called")
        #:             , with     
        self.args = args
        return self
        
    
    def __enter__(self):
        #           
        print("__enter__ called", self.args)
        return 'abcd'

        
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("__exit__ called: exc_type = %s exc_val = %s exc_tb = %s "\
              % (exc_type, exc_val, exc_tb))
        return "exited"


def test1():
    c = ConMgr()
    with c('pppp') as tmp:
        print(tmp)
        print("haha")
        assert 1>2
        print(3)

test1()

出力結果は次のとおりです.
__init__ called
__call__ called
('__enter__ called', ('pppp',))
abcd
haha
__exit__ called: exc_type = <type 'exceptions.AssertionError'> exc_val =  exc_tb = <traceback object at 0x7f911003b128> 

まず、ここでのc()はクラスの一例であり、generatorではなく普通のクラスであることに注意してください.c('pppppp')が実行されると、__が呼び出されるcall__関数,_call__関数は急いで入力したパラメータを保存し、withブロックに入ったら、呼び出し_enter__時にパラメータを出します.
また_call__関数はselfを返さなければなりません.withブロックが実行されるとself._が呼び出されるからです.exit__()selfを返さないと見つかりません_exit__で行ないます.
そしてas文のtmp値は実際には_enter__の戻り値を返して、何を返してもいいです.どうでもいいです.たとえ閉パッケージを渡しても.ここの良いアイデアは、前のargsをtmpに伝えることです.
最後に、assert 1>2でエラーが発生した後、withブロックが実行されずに呼び出されます_.exit__関数です.この関数のパラメータにより,異常処理を実現した.
次にpythonのcontextlibというモジュールを紹介します.
知らない人もいるかもしれませんが、このモジュールには主軸機能がなく、主にwith文をめぐって、便利なutil関数の操作を提供しています.
このモジュールにはcontextmanagerの装飾器があります.それは私たちが前にclassを作成してから補充するのを省くことができます.enter__および_exit__工場モードを利用してgeneratorを生成し、with文を便利に使用することができます.
公式contextlibモジュールの機能について、自分でパクリ版を作ることができるかどうか、詳しくは
以下