详解Python with/as使用说明

作者:骏马金龙 时间:2022-10-29 08:01:26 

with/as

使用open打开过文件的对with/as都已经非常熟悉,其实with/as是对try/finally的一种替代方案。

当某个对象支持一种称为"环境管理协议"的协议时,就会通过环境管理器来自动执行某些善后清理工作,就像finally一样:不管中途是否发生异常,最终都会执行某些清理操作。

用法:


with expression [as var]:
with_block_code

当expression返回的对象是支持环境管理协议的时候,就可以使用with。as var是可选的,如果不使用as var,expression返回对象将被丢弃,如果使用as var,就会将expression的返回对象赋值给变量var。

整个流程大致如下:先评估expression,如果支持环境管理协议,然后开始with/as语句块结构,当准备退出with语句块的时候,将执行对象中定义的善后操作。工作机制的细节见下文。

例如,open()返回的文件对象是支持环境管理协议的,所以可以用with/as来安全地打开文件:


with open(r'd:\a\b\c\a.log') as logfile:
for line in logfile:
 print(line)
 ...more code here...

整个过程是先open(),然后with/as,输出每一行后将要退出with语句块的时候,环境管理器根据文件对象中定义的操作关闭文件。

它实际上等价于:


myfile = open(r'd:\a\b\c\a.log')
try:
for line in myfile:
 print(line)
 ...more code here...
finally:
myfile.close()

虽然在文件不被引用之后,垃圾回收器会自动回收这个文件对象,但是垃圾回收器的回收操作是有等待时间的。换句话说,如果不使用with/as打开文件,也不显示close()关闭文件,那么这个文件很可能会在用完之后保持空闲一段时间,然后才被垃圾回收器回收。

with/as不仅用于文件打开/关闭,锁操作也支持环境管理协议,也就是说,在有需要的时候会自动释放锁资源。

嵌套多个环境管理器

在python 3.1之后,with as支持多个环境管理器,使用逗号隔开即可。


with A() as a, B() as b:
...statements...

它等价于嵌套的with:


with A() as a:
with B() as b:
 ...statements...

多环境管理器管理的多个对象会在with语句块中出现异常的时候,或者执行完with语句块的时候全部自动被清理(例如文件关闭操作)。

例如,打开两个文件,将它们的内容通过zip()合并在一起,并且同时关闭它们:


with open('a.file') as f1, open('b.file') as f2:
for pair in zi[(f1, f2):
 print(pair)

自定义环境管理器

无论是文件还是锁,都是别人已经写好了环境管理器的对象。我们自己也可以写环境管理器,让它可以使用with/as,这实际上属于运算符重载的范畴。

要写自己的环境管理器,先了解with/as的工作机制的细节:

  1. 先评估expression,评估的返回结果是一个对象,这个对象要具有 __enter__ __exit__ 方法,返回的对象称为"环境管理器"

  2. 然后调用环境管理器的 __enter__ 方法。 __enter__ 方法的返回值赋值给 as 指定的变量,或者直接丢弃(没有使用as)

  3. 然后执行with语句块中的内容

  4. 如果执行with语句块中的内容时抛出了异常,将调用 __exit__(type,value,traceback) 方法,其中这3个和异常相关的参数来源于 sys.exc_info 。如果 __exit__ 返回值为False,则会自动重新抛异常以便传播异常,否则异常被认为合理处理

  5. 如果with语句块中的内容没有抛异常,则直接调用 __exit__(None,None,None) ,即这三个参数都传递为None值

看一个简单的示例:


class TraceBlock:
def message(self, arg):
 print('running ' + arg)

def __enter__(self):
 print('starting with block')
 return self

def __exit__(self, exc_type, exc_value, exc_tb):
 if exc_type is None:
  print('exited normally\n')
 else:
  print('raise an exception! ' + str(exc_type))
  return False

上面的 __enter__ 方法返回的对象会赋值给as关键字指定的变量,在这个示例中即将对象自身返回。如果有需求,可以返回其它对象。

上面的 __exit__ 中,如果异常的类型为None,说明with语句块中的语句执行过程没有抛异常,正常结束即可。但是如果有异常,则要求返回False,实际上上面的 return False 可以去掉,因为函数没有return时默认返回None,它的布尔值代表的就时False。

测试下:


with TraceBlock() as action:
action.message("test 1")
print("reached")

print('-' * 20, "\n")

with TraceBlock() as action:
action.message("test 2")
raise TypeError
print("not reached")

结果如下:

starting with block
running test 1
reached
exited normally

--------------------

starting with block
running test 2
raise an exception! <class 'TypeError'>
Traceback (most recent call last):
  File "g:/pycode/list.py", line 23, in <module>
    raise TypeError
TypeError

定义环境管理器不是件简单的事。一般来说,如果不是很复杂的需求,直接使用try/finally来定义相关操作即可。

来源:http://www.cnblogs.com/f-ck-need-u/p/10111121.html

标签:Python,with/as
0
投稿

猜你喜欢

  • Vue.js 2.5新特性介绍(推荐)

    2024-05-13 09:09:00
  • 浅谈keras中的后端backend及其相关函数(K.prod,K.cast)

    2021-07-04 08:53:54
  • Python中的 enum 模块源码详析

    2021-11-19 04:11:10
  • DJango的创建和使用详解(默认数据库sqlite3)

    2024-01-24 20:24:39
  • Python实现的FTP通信客户端与服务器端功能示例

    2023-10-02 21:36:01
  • 修改、删除数据记录(DELETE\\UPDATE)

    2009-02-27 15:50:00
  • Python编程图形库之Pillow使用方法讲解

    2022-04-07 06:10:57
  • 使用phpMyAdmin修改MySQL数据库root用户密码的方法

    2023-11-20 02:12:13
  • python创建文件时去掉非法字符的方法

    2023-10-12 02:15:51
  • Django学习笔记之ORM基础教程

    2022-07-25 22:59:07
  • 详解SQL Server的聚焦过滤索引

    2024-01-22 06:15:23
  • ASP.NET教程第一讲 ASP.NET简介

    2007-08-07 11:50:00
  • python进行TCP端口扫描的实现

    2021-04-18 12:33:32
  • 如何让利用Python+AI使静态图片动起来

    2022-06-06 08:15:31
  • 古老的问题:清除浮动

    2009-02-12 11:21:00
  • MySql用DATE_FORMAT截取DateTime字段的日期值

    2024-01-14 02:48:22
  • Python imutils 填充图片周边为黑色的实现

    2021-04-13 04:06:32
  • python点云地面点滤波(Progressive Morphological Filter)算法介绍(PCL库)

    2021-12-23 00:38:29
  • java正则表达式提取数字的方法实例

    2022-07-09 12:49:31
  • Golang 中 omitempty的作用

    2024-04-25 15:13:03
  • asp之家 网络编程 m.aspxhome.com