最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 详解Python中with方法

    正文概述    2020-06-27   264

    在实际的编码过程中,有时有一些任务,需要事先做一些设置,事后做一些清理,这时就需要python with出场了,with能够对这样的需求进行一个比较优雅的处理,最常用的例子就是对访问文件的处理。

    详解Python中with方法

    一般访问文件资源时我们会这样处理:

    f = open(r'c:\test.txt', 'r')
    data = f.read()
    f.close()

    这样写没有错,但是容易犯两个毛病:

    1. 如果在读写时出现异常而忘了异常处理。

    2. 忘了关闭文件句柄

    以下的加强版本的写法:

    f = open(r'c:\test.txt', 'r')
    try:
        data = f.read()
    finally:
        f.close()

    以上的写法就可以避免因读取文件时异常的发生而没有关闭问题的处理了。代码长了一些。

    但使用with有更优雅的写法:

    with open(r'c:\test.txt', 'r') as f:
        data = f.read()

    说明:

    with后面接的对象返回的结果赋值给f。此例当中open函数返回的文件对象赋值给了f.with会自已获取上下文件的异常信息。

    with是如何做到的呢?

    with后面返回的对象要求必须两__enter__()/__exit__()这两个方法,而文件对象f刚好是有这两个方法的,故应用自如。

    pytho中官方定义说明如下(https://docs.python.org/2/reference/datamodel.html#context-managers):

    object.__enter__(self)
    进入与此对象相关的运行时上下文。with语句将将此方法的返回值绑定到语句的AS子句中指定的目标(如果有设置的话)
     
    object.__exit__(self, exc_type, exc_value, traceback)
    退出与此对象相关的运行时上下文。参数描述导致上下文退出的异常。如果上下文运行时没有异常发生,那么三个参数都将置为None。
    如果有异常发生,并且该方法希望抑制异常(即阻止它被传播),则它应该返回True。否则,异常将在退出该方法时正常处理。
    请注意, __exit__()方法不应该重新抛出传入的异常,这是调用者的职责。

    所谓上下文管理协议,就是咱们打开文件时常用的一种方法:with

    __enter__(self):当with开始运行的时候触发此方法的运行

    __exit__(self, exc_type, exc_val, exc_tb):当with运行结束之后触发此方法的运行

    exc_type如果抛出异常,这里获取异常的类型

    exc_val如果抛出异常,这里显示异常内容

    exc_tb如果抛出异常,这里显示所在位置

    下面举例说明他的原理:

    1. 无异常发生时的例子:

    #!/user/bin/env python3
    #-*- coding:utf-8 -*-
     
    class Test:
        def __enter__(self):
            print('__enter__() is call!')
            return self
     
        def dosomething(self):
            print('dosomethong!')
     
        def __exit__(self, exc_type, exc_value, traceback):
            print('__exit__() is call!')
            print(f'type:{exc_type}')
            print(f'value:{exc_value}')
            print(f'trace:{traceback}')
            print('__exit()__ is call!')
     
    with Test() as sample:
        sample.dosomething()
     
    >>
    __enter__() is call!
    dosomethong!
    __exit__() is call!
    type:None
    value:None
    trace:None
    __exit()__ is call!

    以上的实例Text,我们注意到他带有__enter__()/__exit__()这两个方法,当对象被实例化时,就会主动调用__enter__()方法,任务执行完成后就会调用__exit__()方法,另外,注意到,__exit__()方法是带有三个参数的(exc_type, exc_value, traceback), 依据上面的官方说明:如果上下文运行时没有异常发生,那么三个参数都将置为None, 这里三个参数由于没有发生异常,的确是置为了None, 与预期一致。

    相关推荐:《Python视频教程》

    2. 有异常发生时,会抛出异常的例子:

    以下例子在上面稍做了一些修改,让运行时产生异常,看看这三个参数的赋值情况:

    #!/user/bin/env python3
    #-*- coding:utf-8 -*-
     
    class Test:
        def __enter__(self):
            print('__enter__() is call!')
            return self
     
        def dosomething(self):
            x = 1/0
            print('dosomethong!')
     
        def __exit__(self, exc_type, exc_value, traceback):
            print('__exit__() is call!')
            print(f'type:{exc_type}')
            print(f'value:{exc_value}')
            print(f'trace:{traceback}')
            print('__exit()__ is call!')
            # return True
     
     
    with Test() as sample:
        sample.dosomething()
    >>
    __enter__() is call!
    Traceback (most recent call last):
    __exit__() is call!
    type:<class 'ZeroDivisionError'>
      File "C:/Users/xxx/PycharmProjects/Test1/test.py", line 23, in <module>
    value:division by zero
        sample.dosomething()
    trace:<traceback object at 0x000001C08CF32F88>
      File "C:/Users/xxx/PycharmProjects/Test1/test.py", line 10, in dosomething
    __exit()__ is call!
        x = 1/0
    ZeroDivisionError: division by zero

    从结果可以看出, 在执行到dosomethong时就发生了异常,然后将异常传给了__exit__(), 依据上面的官方说明:如果有异常发生,并且该方法希望抑制异常(即阻止它被传播),则它应该返回True。否则,异常将在退出该方法时正常处理。当前__exit__并没有写明返回True,故会抛出异常,也是合理的,但是正常来讲,程序应该是不希望它抛出异常的,这也是调用者的职责,我们将再次修改__exit__, 将其返回设置为True。

    3. 有异常发生时,不再抛出异常的例子:

    # 在上面的例子上做点修改.
    #!/user/bin/env python3
    #-*- coding:utf-8 -*-
     
    class Test:
        def __enter__(self):
            print('__enter__() is call!')
            return self
     
        def dosomething(self):
            x = 1/0
            print('dosomethong!')
     
        def __exit__(self, exc_type, exc_value, traceback):
            print('__exit__() is call!')
            print(f'type:{exc_type}')
            print(f'value:{exc_value}')
            print(f'trace:{traceback}')
            print('__exit()__ is call!')
            return True
     
     
    with Test() as sample:
        sample.dosomething()
     
    >>
    __enter__() is call!
    __exit__() is call!
    type:<class 'ZeroDivisionError'>
    value:division by zero
    trace:<traceback object at 0x000001C94E592F88>
    __exit()__ is call!

    从结果看,异常抛出被抑制了,符合预期。


    起源地下载网 » 详解Python中with方法

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元