• 流畅python学习笔记:第十五章:上下文管理器


    在开始本章之前,我们首先来谈谈try…excep..final模块.在Python中,进行异常保护的最多就是用try..except..final.首先来看下下面的代码。进行一个简单的除法运算。为了防止分母为0.所以用到了try…except…finally模块
    def get_result():
        a=3
        b=0
        try:
            b=3/0             #函数主体运算代码
        except BaseException,e:  #当发生异常的时候,跳到这执行
            print e
        finally:           #不管是否发生异常,都执行finally语句
            print b
    if __name__=="__main__":
        get_result()
    E:python2.7.11python.exe E:/py_prj/fluent_python/chapter15.py
    integer division or modulo by zero
    0
    从结果可以看出,打印出了integer division or modulo by zero的失败信息。但是在上面的代码中分支还是太多,有没有一种更为简洁的方法来达到这个效果呢。这就是本章要介绍的with模块。
    我们经常看到python书上在打开文件进行读取的时候代码是下面的样子,并且推荐这样写。原因是能够释放资源,比如在文件用完后自动关闭文件。
    with open('filename','wt') as f:
        f.write("hello world")
    如果我们不用with,那么代码就得按照下面的方式写。代码分支更多一些
    file=open('filename','wt')
    try:
        data=file.read()
    finally:
        file.close()
     
    那么with语句的工作原理是什么呢? 主要是两个模块 __enter__和__exit__。工作流程主要是2步:
    1 紧跟with后面的语句被求值后,返回对象的__enter__()方法被调用,这个方法的返回值将被赋值给as后面的变量
    2 当with后面的代码块全部被执行完之后,将调用前面返回对象的__exit__()方法
    来看下代码的实现:
    class try_with(object):
        def __enter__(self):
            print "in __enter__"
            return "__enter__"
        def
    __exit__(self, exc_type, exc_val, exc_tb):
            print "in __exit__"
    if __name__=="__main__":
        with try_with() as t:
            print "in __main__"
            print
    t
    E:python2.7.11python.exe E:/py_prj/fluent_python/chapter15.py
    in __enter__
    in __main__
    __enter__
    in __exit__
    从执行结果可以看到,首先执行了__enter__,返回”__enter__”并且赋值给t. 然后执行with as后面的代码段。当执行完了后,执行__exit__。另外在__exit__中还有3个参数:exc_type,exc_val,exc_tb. 这些参数是异常场景下才会使用的,我们来把代码修改下:
    class try_with(object):
        def __enter__(self):
            print "in __enter__"
            return
    self
        def __exit__(self, exc_type, exc_val, exc_tb):
            print "type:%s" % exc_type
            print "val:%s" % exc_val
            print "tb:%s" % exc_tb
            print "in __exit__"
        def
    calculate(self):
            ret=1/0
            print ret
    if __name__=="__main__":
        with try_with() as t:
            print "in __main__"
            print
    t.calculate()
    E:python2.7.11python.exe E:/py_prj/fluent_python/chapter15.py
    in __enter__
    in __main__
    type:<type 'exceptions.ZeroDivisionError'>
    val:integer division or modulo by zero
    tb:<traceback object at 0x017F2030>
    in __exit__
    Traceback (most recent call last):
      File "E:/py_prj/fluent_python/chapter15.py", line 31, in <module>
        print t.calculate()
      File "E:/py_prj/fluent_python/chapter15.py", line 13, in calculate
        ret=1/0
    ZeroDivisionError: integer division or modulo by zero
    从结果可以看出:实际上,在with后面的代码块抛出任何异常时,__exit__()方法被执行。正如例子所示,异常抛出时,与之关联的type,value和stack trace传给__exit__()方法,因此抛出的ZeroDivisionError异常被打印出来了。开发库时,清理资源,关闭文件等等操作,都可以放在__exit__方法当中。因此,Python的with语句是提供一个有效的机制,让代码更简练,同时在异常产生时,清理工作更简单。 
    看到这里我们再回想下之前的文件打开代码,这时可以理解了为什么书中都推荐用with打开。在open中其实是实现了__enter__和__exit__语句来保障文件的正确打开和关闭
    with open('filename','wt') as f:
        f.write("hello world")
    那么我们是否可以自定义一个上下文管理器呢?这里python也提供了模块让我们来自定义,这就是@contextmanager装饰器。我们来看下代码@contextmanagdef file_open(path)
        try:
            f=open('filename','wt')
            yield f
        except BaseException,e
            print e
        finally:
            print 'close file'
           
    f.close()

    if __name__=="__main__":
        with file_open() as file_obj:
            file_obj.write("hello world")

    我们从contextlib模块中引入contextmanager,然后装饰我们所定义的file_open函数。这就允许我们使用Python的with语句来调用file_open函数。在函数中,我们打开文件,然后通过yield,将其传递出去,最终主调函数可以使用它。

    一旦with语句结束,控制就会返回给file_open函数,它继续执行yield语句后面的代码。这个最终会执行finally语句--关闭文件。如果我们在打开文件时遇到了OSError错误,它就会被捕获,最终finally语句依然会关闭文件句柄。

  • 相关阅读:
    vue-cli的npm run build的常见问题
    es6 Symbol
    es6 对象的扩展
    es7 函数绑定
    es6 箭头函数
    学习weex遇见非常奇怪的问题
    微信
    java面试题
    PHP面试题
    Android
  • 原文地址:https://www.cnblogs.com/zhanghongfeng/p/7266085.html
Copyright © 2020-2023  润新知