理解Python中的with…as…语法

2023-11-11

更详细的参考:

http://www.ibm.com/developerworks/cn/opensource/os-cn-pythonwith/

http://blog.csdn.net/suwei19870312/article/details/23258495


使用语言的好特性,而不是那些糟糕的特性————不知道谁说的

好久不学习python的语法了,上次去面试,和面试官聊到了python中的with-as statement(也称context manager),挺感兴趣的,这两天学习了一番,收获颇丰在此分享。

先说明一个常见问题,文件打开:

try :
     f = open ( 'xxx' )
     do something
except :
     do something
finally :
     f.close()

其实我个人不止一次在网上看到有这么写的了,这个是错的。
首先正确的如下:

try :
     f = open ( 'xxx' )
except :
     print 'fail to open'
     exit( - 1 )
try :
     do something
except :
     do something
finally :
     f.close()

很麻烦不是么,但正确的方法就是这么写。
我们为什么要写finally,是因为防止程序抛出异常最后不能关闭文件,但是需要关闭文件有一个前提就是文件已经打开了。
在第一段错误代码中,如果异常发生在f=open(‘xxx’)的时候,比如文件不存在,立马就可以知道执行f.close()是没有意义的。改正后的解决方案就是第二段代码。

好了言归正转,开始讨论with语法。

首先我们从下面这个问题谈起,try-finally的语法结构:

set things up
try :
     do something
finally :
     tear things down

这东西是个常见结构,比如文件打开,set things up就表示f=open('xxx')tear things down就表示f.close()。在比如像多线程锁,资源请求,最终都有一个释放的需求。Try…finally结构保证了tear things down这一段永远都会执行,即使上面do something得工作没有完全执行。

如果经常用这种结构,我们首先可以采取一个较为优雅的办法,封装!

def controlled_execution(callback):
     set things up
     try :
         callback(thing)
     finally :
         tear things down
 
def my_function(thing):
     do something
 
controlled_execution(my_function)

封装是一个支持代码重用的好办法,但是这个办法很dirty,特别是当do something中有修改一些local variables的时候(变成函数调用,少不了带来变量作用域上的麻烦)。

另一个办法是使用生成器,但是只需要生成一次数据,我们用for-in结构去调用他:

def controlled_execution():
     set things up
     try :
         yield thing
     finally :
         tear things down
         
for thing in controlled_execution():
     do something with thing

因为thing只有一个,所以yield语句只需要执行一次。当然,从代码可读性也就是优雅的角度来说这简直是糟糕透了。我们在确定for循环只执行一次的情况下依然使用了for循环,这代码给不知道的人看一定很难理解这里的循环是什么个道理。

最终的python-dev团队的解决方案。(python 2.5以后增加了with表达式的语法)

class controlled_execution:
     def __enter__( self ):
         set things up
         return thing
     def __exit__( self , type , value, traceback):
         tear things down
         
with controlled_execution() as thing:
         do something

在这里,python使用了with-as的语法。当python执行这一句时,会调用__enter__函数,然后把该函数return的值传给as后指定的变量。之后,python会执行下面do something的语句块。最后不论在该语句块出现了什么异常,都会在离开时执行__exit__。
另外,__exit__除了用于tear things down,还可以进行异常的监控和处理,注意后几个参数。要跳过一个异常,只需要返回该函数True即可。下面的样例代码跳过了所有的TypeError,而让其他异常正常抛出。

def __exit__( self , type , value, traceback):
     return isinstance (value, TypeError)

在python2.5及以后,file对象已经写好了__enter__和__exit__函数,我们可以这样测试:

>>> f = open ( "x.txt" )
>>> f
< open file 'x.txt' , mode 'r' at 0x00AE82F0 >
>>> f.__enter__()
< open file 'x.txt' , mode 'r' at 0x00AE82F0 >
>>> f.read( 1 )
'X'
>>> f.__exit__( None , None , None )
>>> f.read( 1 )
Traceback (most recent call last):
     File "<stdin>" , line 1 , in <module>
ValueError: I / O operation on closed file

之后,我们如果要打开文件并保证最后关闭他,只需要这么做:

with open ( "x.txt" ) as f:
     data = f.read()
     do something with data

如果有多个项,我们可以这么写:

with open ( "x.txt" ) as f1, open ( 'xxx.txt' ) as f2:
     do something with f1,f2

上文说了__exit__函数可以进行部分异常的处理,如果我们不在这个函数中处理异常,他会正常抛出,这时候我们可以这样写(python 2.7及以上版本,之前的版本参考使用contextlib.nested这个库函数):

try :
     with open ( "a.txt" ) as f :
         do something
except xxxError:
     do something about exception

总之,with-as表达式极大的简化了每次写finally的工作,这对保持代码的优雅性是有极大帮助的。

感谢以下参考资料:
stackoverflow: Catching an exception while using a Python ‘with’ statement
Understanding Python’s “with” statement
python docs:
http://docs.python.org/2/reference/compound_stmts.html#with
http://docs.python.org/2/reference/datamodel.html#context-managers
http://docs.python.org/2/library/contextlib.html#contextlib.nested



转载于:https://my.oschina.net/goopand/blog/420142

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

理解Python中的with…as…语法 的相关文章

随机推荐

  • Redis多机数据库实现

    Redis多机数据库实现 为 Redis设计与实现 笔记 复制 客户端可以使用SLAVEOF命令将指定服务器设置为该服务器的主服务器 127 0 0 1 12345 gt SLAVEOF 127 0 0 1 6379 127 0 0 1 6
  • Date类(Date、SimpleDateFormat和Calendar)使用

    1 Date类与long数据类型的转型 2 SimpleDateFormat类的使用 3 Calendar类的使用 如果要操作日期一定要使用日期的处理类 1 Java util Date类 范例 package com lohas demo
  • Win10/Win11子系统(二)——深度学习环境搭建:WSL2+Ubuntu20.04+CUDA10.1+pytorch1.8.1+pycharm

    windows子系统wsl2深度学习环境配置 前言 一 准备工作 显卡驱动 二 CUDA10 1配置 1 下载安装 2 设置环境变量 三 cudnn配置 3 检验安装 四 安装Anaconda 五 安装pytorch 六 安装pycharm
  • hexo实现背景花瓣飞舞效果

    效果 步骤 在source目录下js文件中新增petal js文件 var RENDERER INIT CHERRY BLOSSOM COUNT 30 MAX ADDING INTERVAL 10 init function this se
  • 在PLC中USINT和BYTE的区别

    这两种数据类型的大小和使用范围一样 大小是8位 范围是0到255 但是BYTE可以直接对数据的某一位操作 比如BYTE类型 byData X5 TRUE 表示把byData二进制数据的第五位直接置为1 与BYTE功能类似的16和32位数据类
  • 什么是“懒加载”(Lazy Loading)?

    懒加载 也被叫作 延迟价值 它的核心思想是把对象的实例化延迟到真正调用该对象的时候 这样做的好处是可以减轻大量对象在实例化时对资源的小号 而不是在程序初始化的时候就预先将对象实例化 另外 懒加载 可以将对象的实例化代码从初始化方法中独立出来
  • EasyGBS针对数据库删除级联数据后的无效数据进行的优化

    EasyGBS国标视频云服务可支持通过国标GB28181协议将设备接入 实现视频的实时监控直播 录像 语音对讲 云存储 告警 级联等功能 同时也支持将接入的视频流进行全终端 全平台分发 分发的视频流包括RTSP RTMP FLV HLS W
  • linux学习,配置bond

    什么是bond bond是一种虚拟网卡的技术 可以把几块网卡联系起来 虚拟成一块网卡来对外提供服务 通俗一点就是服务器两个网口怼两根线 把这两个真实存在的网口绑定成一个虚拟的网卡 叫bond0 然后把ip配到bond0 它的网速就从1000
  • 有什么资格抱怨?

    那些轻描淡写抱怨没有机会说自己苦逼的人 请你们扪心自问 当 小四川 捧着一本 操作系统 睡着的时候 你们在干吗 当 老灵通 这个五音不全的人 为了英语发音稍微好听点 把一段话背诵上百遍时 你们在干吗 当我捧着字典 啃着几斤重的英文版 管理会
  • VSCode最新版安装教程(非常详细),从零基础入门到精通,看这篇就够了

    VSCode 简介 Visual Studio Code 简称 VS Code VSC 是微软公司推出的一款免费开源的现代化轻量级代码编辑器 支持几乎所有主流的开发语言的语法高亮 智能代码补全 GIT 等特性 支持插件扩展等等 推荐理由 比
  • linux web项目部署到tomcat服务器

    192 168 1 11 192 168 1 12 192 168 1 13 tomcat tomcat123 ll 查看当前目录 cd 进入目录 ps ef grep tomcat query 查看进程 查看进程号 kill 9 进程号
  • 锂电池充电——NTC温度控制电路

    目录 JEITA标准 the Japan Electronics and Information Technology Industries Association NTC 负温度系数热敏电阻 型号 103AT 2 阻值 温度采样电路 TS
  • 联表查询和嵌套查询—读懂数据库仓储

    数据仓储不像java C JS等开发语言 而是数据库仓储更多用于对接产品工作 查询数据 分析数据 得出产品未来发展方向 与产品经理相关联 而联表查询和嵌套查询作为数据库基础的查询方法 学习使用 方便技术人员从数据库的角度收集数据 给产品经理
  • 配置Sub-VLAN跨交换机的Super-VLAN

    示例图 一 实验目的 1 Sub VLAN跨交换机的Super VLAN 二 注意事项 1 必须先创建配置每个sub vlan 再创建 配置Super vlan 2 当Super vlan开启了 VLAN内ARP代理功能时 各个sub vl
  • java定义一个全局map_Java中关于Map的九大问题

    通常来说 Map是一个由键值对组成的数据结构 且在集合中每个键是唯一的 下面就以K和V来代表键和值 来说明一下java中关于Map的九大问题 1 将Map转换为List类型 在java中Map接口提供了三种集合获取方式 Key set va
  • VS2015同时将调试信息输出到终端和文件

    下载wtee https github com gvalkov wtee 将wtee exe放到 C Windows System32 目录下 在VS工程的 属性页 gt 配置属性 gt 调试 gt 命令参数一栏的最后面添加 wtee my
  • 请求跨域 CORS policy: No ‘Access-Control-Allow-Origin‘

    目录 1 跨域和同源 2 CORS 跨域资源共享 解决跨域 2 1 前端解决 不推荐 2 2 Nginx 解决跨域 2 3 tomcat 解决跨域 2 4 SpringBoot 服务解决跨域 3 总结 如在浏览器控制台看到类似于下边的报错
  • tomcat下部署jenkins

    tomcat简介 Tomcat是Apache 软件基金会 Apache Software Foundation 的Jakarta 项目中的一个核心项目 由Apache Sun 和其他一些公司及个人共同开发而成 由于有了Sun 的参与和支持
  • 敏捷开发---故事拆解

    很多时候 故事拆解利用模块化处理方式执行 但是跟多事小团队内部协商进行ac处理 体验问题的处理 这种弊端是 缺乏故事完整性 建议 采用全面鱼骨特性 进行小团队作战
  • 理解Python中的with…as…语法

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 更详细的参考 http www ibm com developerworks cn opensource os cn pythonwith http blog csdn n