Python 中的上下文管理器

系统 1675 0

Python 中的上下文管理器

            
              
                with
              
               expression 
              
                [
              
              
                as
              
               target
              
                ]
              
              
                :
              
              
                with
              
              
                -
              
              body

            
          

上下文管理器是为with 语句而生。只要实现了上下文管理器协议 __enter__ __exit__ ,就可以使用with语句。

__enter__ 通常执行一些初始化操作,并且该函数的返回值会赋值给可选的 as target 中的 target 变量。

__exit__ 执行资源清理工作。它接收三个参数,异常类型,异常实例,和异常栈,根据这些异常信息, __exit__ 可以选择进行相应的异常处理,并默认抛出异常。如果我们在让 __exit__ 返回True,相当于告诉python:这些异常我都已经处理了,都在掌控之中,您老不必操心。

除了自定义类手动实现两个特殊方法外,还有另一种途径实现一个上下文管理器。
标准库 contextlib 中提供了一个 @contextmanager 可以方便的把一个协程函数包装成一个上下文管理器。
《Fluent Python》 书中一个好玩的例子:

            
              @contextmanager

              
                def
              
              
                f
              
              
                (
              
              
                )
              
              
                :
              
              
                import
              
               sys
    
              
                print
              
              
                (
              
              
                '欢迎来到镜像的世界'
              
              
                )
              
              
    origin_print 
              
                =
              
               sys
              
                .
              
              stdout
              
                .
              
              write
    sys
              
                .
              
              stdout
              
                .
              
              write 
              
                =
              
              
                lambda
              
               x
              
                :
              
               origin_print
              
                (
              
              x
              
                [
              
              
                :
              
              
                :
              
              
                -
              
              
                1
              
              
                ]
              
              
                )
              
              
                # 初始化:替换系统输入。运行中动态修改、添加类的方法————猴子补丁。
              
              
                yield
              
              
                '这里的打印都是反向输出'
              
              
    sys
              
                .
              
              stdout
              
                .
              
              write 
              
                =
              
               origin_print  
              
                # 退出时:恢复系统输入
              
              
                print
              
              
                (
              
              
                'Finally I come back'
              
              
                )
              
              

mirror_world 
              
                =
              
               f
              
                (
              
              
                )
              
              
                with
              
               mirror_world 
              
                as
              
               target
              
                :
              
              
                print
              
              
                (
              
              target
              
                )
              
            
          

输出结果:

            
              欢迎来到镜像的世界
出输向反是都印打的里这
Finally I come back

            
          

协程函数中yield之前的所有代码相当于 __enter__ 部分的工作,执行初始化,执行中动态替换了系统的输出功能(猴子补丁特性)。
并且把一个结果绑定到 with...as target target 。至此协程函数交出代码执行权,python转而去执行with-block里面的代码。执行完with-block 开始执行yield之后的代码——相当于 __exit__ 的工作,执行资源清理。

至此我们好像实现了一个功能正常的上下文管理器。但别忘了还有异常捕获的机制。。。

在终端中执行 mirror_world 时,如果with-block中抛出了一个异常,会导致资源清理工作没有进行,之后所有的print仍是反向输出。我们还应做的是把yield行的代码包裹在一个 try...except...finally 中,在finally-bolck中执行资源清理工作,以保证正常退出(鬼知道用户会在with-block搞什么蛇皮…)。


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

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

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