python中的上下文管理器和with语句块

系统 494 0

上下文管理器对象存在的目的就是管理with语句。上下文管理器协议包含__enter__ 和__exit__ 两个方法。with 语句开始运行时,会在上下文管理器对象上调用__enter__ 方法。with 语句运行结束后,会在上下文管理器对象上调用__exit__ 方法

来看一个例子,把文件对象当成上下文管理器使用

            
              
                with
              
              
                open
              
              
                (
              
              
                'test.dat'
              
              
                )
              
              
                as
              
               fp
              
                :
              
              
    secc 
              
                =
              
               fp
              
                .
              
              read
              
                (
              
              
                20
              
              
                )
              
              
                >>
              
              
                >
              
              
                len
              
              
                (
              
              src
              
                )
              
              
                20
              
              
                >>
              
              
                >
              
               fp 

              
                <
              
              _io
              
                .
              
              TextIOWrapper name
              
                =
              
              
                'mirror.py'
              
               mode
              
                =
              
              
                'r'
              
               encoding
              
                =
              
              
                'UTF-8'
              
              
                >
              
              
                >>
              
              
                >
              
               fp
              
                .
              
              closed
              
                ,
              
               fp
              
                .
              
              encoding 

              
                (
              
              
                True
              
              
                ,
              
              
                'UTF-8'
              
              
                )
              
              
                """
但是不能在fp 上执行I/O 操作,因为在with 块的末尾,调用TextIOWrapper.__exit__
方法把文件关闭了。
"""
              
              
                >>
              
              
                >
              
               fp
              
                .
              
              read
              
                (
              
              
                60
              
              
                )
              
              
Traceback 
              
                (
              
              most recent call last
              
                )
              
              
                :
              
              
File 
              
                "
                
                  "
                
              
              
                ,
              
               line 
              
                1
              
              
                ,
              
              
                in
              
              
                <
              
              module
              
                >
              
              
ValueError
              
                :
              
               I
              
                /
              
              O operation on closed 
              
                file
              
              
                .
              
            
          

执行with后面的表达式得到的结果是上下文管理器对象,不过,把值绑定到目标变量上(as子句)是上下文管理器调用__enter__方法的结果

来看一个例子,自己实现一个上下文管理器

            
              
                class
              
              
                Sample
              
              
                (
              
              
                )
              
              
                :
              
              
                def
              
              
                __enter__
              
              
                (
              
              self
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                "in __enter__"
              
              
                )
              
              
                return
              
               self
        
    
              
                def
              
              
                __exit__
              
              
                (
              
              self
              
                ,
              
               exc_type
              
                ,
              
               exc_val
              
                ,
              
               exc_tb
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                "in __exit__"
              
              
                )
              
              
                def
              
              
                do_something
              
              
                (
              
              self
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                "i am doing something"
              
              
                )
              
              
                >>
              
              
                >
              
              
                with
              
               Sample
              
                (
              
              
                )
              
              
                as
              
               sample
              
                :
              
              
        sample
              
                .
              
              do_something
              
                (
              
              
                )
              
              
                in
              
               __enter__
i am doing something

              
                in
              
               __exit__

            
          

真个过程运行如下,enter()方法被执行,enter()方法返回值,在这里是类自身,执行代码块sample.do_something(), 最后是exit()方法被调用

contextlib模块中的使用工具

@contextmanager 装饰器能减少创建上下文管理器的样板代码量,因为不用编写一个完整的类,定义__enter__ 和__exit__方法,而只需实现有一个yield 语句的生成器,生成想让__enter__ 方法返回的值。
在使用@contextmanager 装饰的生成器中,yield语句的作用是把函数的定义体分成两部分**:yield 语句前面的所有代码在with 块开始时(即解释器调用__enter__方法时)执行,yield 语句后面的代码在with 块结束时(即调用__exit__ 方法时)执行**

看一个使用contextmanager实现上下文管理器的例子

            
              
                import
              
               contextlib
@contextlib
              
                .
              
              contextmanager

              
                def
              
              
                Sample
              
              
                (
              
              
                )
              
              
                :
              
              
                def
              
              
                do_something
              
              
                (
              
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                'i am doing something'
              
              
                )
              
              
                print
              
              
                (
              
              
                "in __enter__"
              
              
                )
              
              
                yield
              
               do_something
    
              
                print
              
              
                (
              
              
                "in exit"
              
              
                )
              
              
                >>
              
              
                >
              
              
                with
              
               Sample
              
                (
              
              
                )
              
              
                as
              
               sample
              
                :
              
              
        sample
              
                (
              
              
                )
              
              
                in
              
               __enter__
i am doing something

              
                in
              
               __exit__

            
          

更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请请扫描上面二维码支持博主1元、2元、5元等您想捐的金额吧,狠狠点击下面给点支持吧

发表我的评论
最新评论 总共0条评论