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

文件读写初级:

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

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

存在两个问题:

1. 如果在读写时出现异常而忘了异常处理。
2. 忘了关闭文件句柄

文件读写中级:

以下的加强版本的写法:

  f = open(r'c:\mytest.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语句的工作原理

__enter__()/__exit__()这两个方法

with后面返回的对象要求必须有这两个方法,而文件对象f刚好是有这两个方法的。

object.__enter__(self)

进入与此对象相关的运行时上下文。with语句将将此方法的返回值绑定到语句的AS子句中指定的目标(如果有设置的话)

object.__exit__(self, exc_type, exc_value, traceback)

退出与此对象相关的运行时上下文。参数描述导致上下文退出的异常。如果上下文运行时没有异常发生,那么三个参数都将置为None。
如果有异常发生,并且该方法希望抑制异常(即阻止它被传播),则它应该返回True。否则,异常将在退出该方法时正常处理。

注意:

__exit__()方法不应该重新抛出传入的异常,这是调用者的职责。

下面,以3个实例讲解:

1、无异常情况:

 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, 与预期一致。

2、出现并抛出异常:

 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、出现异常,阻止异常抛出:

 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!

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

---------------------
本文为CSDN博主「五力」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lxy210781/article/details/81176687

Python3 之 with语句(高效、便捷)的更多相关文章

  1. MySQL语句高效写法整理

    优先使用INNER JOIN 多表关联查询,扫描的行尽量少         关联的时候下条件减少扫描的行数 SELECT     ... FROM     ad_ad_summary_for_pos_ ...

  2. APPLE框架之高效便捷的Repository解决方案

    原文地址:http://perfy315.iteye.com/blog/1460226 Spring Data JPA 转至:http://note.sdo.com/u/855924134/n/P15 ...

  3. Java实现高效便捷还容易懂的排序算法

    PS:我现在越来越认为排序大法是,很深的算法了,就是简单的几个步骤,网上的大佬们能给你玩出花来(ง •_•)ง public class zimuzhenlie2 { public static vo ...

  4. python3之if与语句

    获得更多资料欢迎进入我的网站或者 csdn或者博客园 本节主要介绍python,if条件语句,以及用法.下面附有之前的文章: 语句快介绍 语句快并非一种语句,是通过缩进形成的语句集合: 可以使用的缩进 ...

  5. Javascript之高效编程

    前言: Javascript绝对是最火的编程语言之一,一直具有很大的用户群,具有广泛的应用前景.而在前端开发中,它也是三驾马车之一,并且是最重要的一环.要想给用户提供更流畅的操作体验,更友好的交互,对 ...

  6. Python3分析sitemap.xml抓取导出全站链接

    最近网站从HTTPS转为HTTP,更换了网址,旧网址做了301重定向,折腾有点大,于是在百度站长平台提交网址,不管是主动推送还是手动提交,前提都是要整理网站的链接,手动添加太麻烦,效率低,于是就想写个 ...

  7. python3爬虫_环境安装

    一.环境安装 1.python3安装 官网:https://www.python.org/downloads/ 64 位系统可以下载 Windows x86-64 executable install ...

  8. python2.+进化至python3.+ 语法变动差异(不定期更新)

    1.输出 python2.+ 输出: print "" python3.+ 输出: print ("") 2.打开文件 python2.+ 打开文件: file ...

  9. SQL基本语句的优化10个原则

    原则一:尽量避免在列上进行运算,这样会导致索引失效. 例如: ; 优化: SELECT * FROM table WHERE d >= '2011-01-01'; 原则二:使用JOIN时,应该用 ...

随机推荐

  1. Django 从零开始

    Django在Python的web开发框架中属于重量级的框架,功能多而全,但是相对的体积和坑也会比较多,但是其实学习Python的web开发个人觉得Django其实会比Flask好上手,特别是0基础的 ...

  2. redis集群之Codis

    在大数据高并发场景下,单个 Redis 实例往往会显得捉襟见肘.首先体现在内存上,单个 Redis 的内存不宜过大,内存太大会导致 rdb 文件过大,进一步导致主从同步时全量同步时间过长,在实例重启恢 ...

  3. Yii ActiveRecord用法记录备忘

    ActiveRecord 使用方法 Example1 in查询 $criteria = new CDbCriteria(); $criteria->select = $select; $crit ...

  4. ansible模块之yum、pip、service、corn、user、group

    ansible相关模块 yum rpm 和yum 的区别 rpm:全称redhat package manager (红帽包管理器) 不能解决包之间的依赖关系 yum:可以解决依赖关系 yum 源配置 ...

  5. 使用 EW 作Socks5代理

    简介: EarthWorm是一款用于开启 SOCKS v5 代理服务的工具,基于标准 C 开发,可提供多平台间的转接通讯,用于复杂网络环境下的数据转发. 主页: http://rootkiter.co ...

  6. Java 8 - 行为参数化

    前言: 以下内容来源于java8实战一书,我将里面学习的内容做一个整理,方便没空读书的小伙伴快速入门实战java8 正文: 假设一个果农收获了一园的苹果,他需要你根据他的条件筛选出满意的苹果 首先我们 ...

  7. [Java] 生成二维码源码,可以在二维码中间加logo,底部可以加文字介绍

    链接:https://pan.baidu.com/s/1bc1h-ix-No-2o9Ysd4_B3Q提取码:0ad4

  8. wpf使用技巧

    1.设置资源 <Window.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries ...

  9. mysql多种备份与恢复方式一

    基于mysql社区版5.7,严重声明:本文中图方便直接写入了-p数据库密码,在生产环境中如果指定了一定要使用history -C清空历史命令记录哦,所有博客作者原创纯手打,转载一定要注明本博客链接,感 ...

  10. vim编辑器介绍

    所有的 Unix Like 系统都会内建 vi 文书编辑器,其他的文书编辑器则不一定会存在. 但是目前我们使用比较多的是 vim 编辑器. vim 具有程序编辑的能力,可以主动的以字体颜色辨别语法的正 ...