在实际的编码过程中,有时有一些任务,需要事先做一些设置,事后做一些清理,这时就需要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. next day

    #_*_coding:utf_*_#!/usr/bin/env python now_day=input('当前某一天:').format('%Y.%m.%d')%%输入日期(年.月.日) year= ...

  2. Visual Studio Code 添加C/C++编译功能

    VS Code作为一个文本/代码编辑器,相较于VS比较轻量化,而且可以支持C/C++.Python等多种语言,并具有丰富的拓展模块. 但是作为一个编辑器,在VS Code上安装C/C++模块之后,并不 ...

  3. SpringBoot整合RabbitMq(二)

           本文序列化和添加package参考:https://www.jianshu.com/p/13fd9ff0648d RabbitMq安装 [root@topcheer ~]# docker ...

  4. 设计模式C++描述----21.解释器(Iterpreter)模式

    一. 解释器模式 定义:给定一个语言,定义它的文法的一种表示,并定一个解释器,这个解释器使用该表示来解释语言中的句子. 结构如下: 代码如下: //包含解释器之外的一些全局信息 class Conte ...

  5. 关于dt分组、计数、排序的实例

    #region table去重复求和 var query = dt.Rows.Cast<DataRow>() .OrderByDescending(n => n["OPER ...

  6. Mysql 索引类型+索引方法

    MYSQL索引: PRIMARY(唯一且不能为空:一张表只能有一个主键索引). INDEX(普通索引). UNIQUE(唯一性索引). FULLTEXT(全文索引:用于搜索很长一篇文章的时候,效果最好 ...

  7. VS Code 1.40 发布!可自行搭建 Web 版 VS Code!

    今天(北京时间 2019 年 11 月 8 日),微软发布了 Visual Studio Code 1.40 版本.让我们来看看有哪些主要的更新. 自建 Web 版 VS Code 前不久,微软正式发 ...

  8. Web for pentester_writeup之File Upload篇

    Web for pentester_writeup之File Upload篇 File Upload(文件上传) Example 1 直接上传一句话木马,使用蚁剑连接 成功连接,获取网站根目录 Exa ...

  9. 五、docker-compose开锋(docker 三剑客)

    前言 终于写到docker-compose了,其实我最开始接触docker的时候,是因为一个开源项目需要用docker 环境和docke-compose 所以我最先接触的是docker-compse ...

  10. hack the box -- sizzle 渗透过程总结,之前对涉及到域内证书啥的还不怎么了解

     把之前的笔记搬运过来 ---   1 开了443,用smbclient建立空连接查看共享 smbclient -N -L \\\\1.1.1.1 Department Shares Operatio ...