python语言中with as的用法使用详解


Posted in Python onFebruary 23, 2018

With语句是什么?

有一些任务,可能事先需要设置,事后做清理工作。对于这种场景,Python的with语句提供了一种非常方便的处理方式。一个很好的例子是文件处理,你需要获取一个文件句柄,从文件中读取数据,然后关闭文件句柄。
如果不用with语句,代码如下:

file = open("/tmp/foo.txt")
data = file.read()
file.close()

这里有两个问题。一是可能忘记关闭文件句柄;二是文件读取数据发生异常,没有进行任何处理。下面是处理异常的加强版本:

file = open("/tmp/foo.txt")
try:
  data = file.read()
finally:
  file.close()

虽然这段代码运行良好,但是太冗长了。这时候就是with一展身手的时候了。除了有更优雅的语法,with还可以很好的处理上下文环境产生的异常。下面是with版本的代码:

with open("/tmp/foo.txt") as file:
  data = file.read()

with如何工作?

这看起来充满魔法,但不仅仅是魔法,Python对with的处理还很聪明。基本思想是with所求值的对象必须有一个__enter__()方法,一个__exit__()方法。

紧跟with后面的语句被求值后,返回对象的__enter__()方法被调用,这个方法的返回值将被赋值给as后面的变量。当with后面的代码块全部被执行完之后,将调用前面返回对象的__exit__()方法。

下面例子可以具体说明with如何工作:

#!/usr/bin/env python
# with_example01.py
 
class Sample:
  def __enter__(self):
    print "In __enter__()"
    return "Foo"
 
  def __exit__(self, type, value, trace):
    print "In __exit__()"
 
def get_sample():
  return Sample()
 
with get_sample() as sample:
  print "sample:", sample

运行代码,输出如下

In __enter__()
sample: Foo
In __exit__()

正如你看到的,

1. __enter__()方法被执行

2. __enter__()方法返回的值 - 这个例子中是"Foo",赋值给变量'sample'

3. 执行代码块,打印变量"sample"的值为 "Foo"

4. __exit__()方法被调用

with真正强大之处是它可以处理异常。可能你已经注意到Sample类的__exit__方法有三个参数- val, type 和 trace。 这些参数在异常处理中相当有用。我们来改一下代码,看看具体如何工作的。

#!/usr/bin/env python
# with_example02.py
class Sample:
  def __enter__(self):
    return self
 
  def __exit__(self, type, value, trace):
    print "type:", type
    print "value:", value
    print "trace:", trace
 
  def do_something(self):
    bar = 1/0
    return bar + 10
 
with Sample() as sample:
  sample.do_something()

这个例子中,with后面的get_sample()变成了Sample()。这没有任何关系,只要紧跟with后面的语句所返回的对象有__enter__()和__exit__()方法即可。此例中,Sample()的__enter__()方法返回新创建的Sample对象,并赋值给变量sample。

代码执行后:

bash-3.2$ ./with_example02.py
type: <type 'exceptions.ZeroDivisionError'>
value: integer division or modulo by zero
trace: <traceback object at 0x1004a8128>
Traceback (most recent call last):
  File "./with_example02.py", line 19, in <module>
    sample.do_something()
  File "./with_example02.py", line 15, in do_something
    bar = 1/0
ZeroDivisionError: integer division or modulo by zero

实际上,在with后面的代码块抛出任何异常时,__exit__()方法被执行。正如例子所示,异常抛出时,与之关联的type,value和stack trace传给__exit__()方法,因此抛出的ZeroDivisionError异常被打印出来了。开发库时,清理资源,关闭文件等等操作,都可以放在__exit__方法当中。

因此,Python的with语句是提供一个有效的机制,让代码更简练,同时在异常产生时,清理工作更简单。

with-as语句

从python2.6开始,with就成为默认关键字了。With是一个控制流语句,跟if for while try之类的是一类,with可以用来简化try-finally代码,看起来比try finally更清晰,所以说with用很优雅的方式处理上下文环境产生的异常。with关键字的用法如下:

with expression as variable:
  with block

该代码快的执行过程是:

1.先执行expression,然后执行该表达式返回的对象实例的__enter__函数,然后将该函数的返回值赋给as后面的变量。(注意,是将__enter__函数的返回值赋给变量)

2.然后执行with block代码块,不论成功,错误,异常,在with block执行结束后,会执行第一步中的实例的__exit__函数

with-as语句使用举例

(1)打开文件的例子

with-as语句最常见的一个用法是打开文件的操作,如下:

with open("decorator.py") as file:
  print file.readlines()

(2)自定义

with语句后面的对象必须要有__enter__和__exit__方法,如下是一个自定义的例子:

class WithTest():
  def __init__(self,name):
    self.name = name
    pass

  def __enter__(self):
    print "This is enter function"
    return self 

  def __exit__(self,e_t,e_v,t_b):
    print "Now, you are exit"

  def playNow(self):
    print "Now, I am playing"

print "**********"
with WithTest("coolboy") as test:
  print type(test)
  test.playNow() 
  print test.name
print "**********"

上述代码运行的结果如下:

**********
This is enter function
<type 'instance'>
Now, I am playing
coolboy
Now, you are exit
**********

分析以上代码: 一二行,执行open函数,该函数返回一个文件对象的实例,然后执行了该实例的__enter__函数,该函数返回此实例本身,最后赋值给file变量。从456句可以印证。

自定义的类WithTest,重载了__enter__和__exit__函数,就可以实现with这样的语法了,注意在__enter__函数中,返回了self,在__exit__函数中,可以通过__exit__的返回值来指示with-block部分发生的异常是否需要reraise,如果返回false,则会reraise with block异常,如果返回ture,则就像什么也没发生。

上下文管理器contextlib模块对with-as的支持

contextlib 模块提供了3个对象:装饰器 contextmanager、函数 nested 和上下文管理器 closing。使用这些对象,可以对已有的生成器函数或者对象进行包装,加入对上下文管理协议的支持,避免了专门编写上下文管理器来支持 with 语句。

以contextlib的closing来说,closing帮助实现了__enter__和__exit__方法,用户不需要自己再实现这两个方法,但是被closing分装的对象必须提供close方法。contextlib.closing类的实现代码如下:

class closing(object):
  # help doc here
  def __init__(self, thing):
    self.thing = thing
  def __enter__(self):
    return self.thing
  def __exit__(self, *exc_info):
    self.thing.close()

下面是一个使用contextlib.closing的例子:

import contextlib
request_url = ('http://www.sina.com.cn/')
with contextlib.closing(urlopen(request_url)) as response:
  return response.read().decode('utf-8')

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python压缩解压缩zip文件及破解zip文件密码的方法
Nov 04 Python
Python实现Sqlite将字段当做索引进行查询的方法
Jul 21 Python
python实现八大排序算法(1)
Sep 14 Python
python多进程中的内存复制(实例讲解)
Jan 05 Python
Python实现PS滤镜中马赛克效果示例
Jan 20 Python
实践Vim配置python开发环境
Jul 02 Python
详解pandas如何去掉、过滤数据集中的某些值或者某些行?
May 15 Python
基于Python安装pyecharts所遇的问题及解决方法
Aug 12 Python
tensorflow 模型权重导出实例
Jan 24 Python
Python图像阈值化处理及算法比对实例解析
Jun 19 Python
详解python对象之间的交互
Sep 29 Python
使用pandas或numpy处理数据中的空值(np.isnan()/pd.isnull())
May 14 Python
python实现定时自动备份文件到其他主机的实例代码
Feb 23 #Python
Python机器学习算法之k均值聚类(k-means)
Feb 23 #Python
python3调用R的示例代码
Feb 23 #Python
python中kmeans聚类实现代码
Feb 23 #Python
python实现SOM算法
Feb 23 #Python
python实现k-means聚类算法
Feb 23 #Python
python写一个md5解密器示例
Feb 23 #Python
You might like
Smarty结合Ajax实现无刷新留言本实例
2007/01/02 PHP
40个迹象表明你还是PHP菜鸟
2008/09/29 PHP
php mssql 日期出现中文字符的解决方法
2009/03/10 PHP
一步一步学习PHP(4) php 函数 补充2
2010/02/15 PHP
兼容性最强的PHP生成缩略图的函数代码(修改版)
2011/01/18 PHP
php生成EAN_13标准条形码实例
2013/11/13 PHP
php中随机函数mt_rand()与rand()性能对比分析
2014/12/01 PHP
PHP 验证身份证是否合法的函数
2017/02/09 PHP
Javascript下IE与Firefox下的差异兼容写法总结
2010/06/18 Javascript
Jquery实现弹出层分享微博插件具备动画效果
2013/04/03 Javascript
node.js中的dns.getServers方法使用说明
2014/12/08 Javascript
jquery 属性选择器(匹配具有指定属性的元素)
2016/09/06 Javascript
WebSocket实现简单客服聊天系统
2017/05/12 Javascript
将Sublime Text 3 添加到右键中的简单方法
2017/12/12 Javascript
jQuery pagination分页示例详解
2018/10/23 jQuery
JS获取今天是本月第几周、本月共几周、本月有多少天、是今年的第几周、是今年的第几天的示例代码
2018/12/05 Javascript
使用 Vue cli 3.0 构建自定义组件库的方法
2019/04/30 Javascript
JS实现可控制的进度条
2020/03/25 Javascript
Vant 在vue-cli 4.x中按需加载操作
2020/11/05 Javascript
python绘图库Matplotlib的安装
2014/07/03 Python
Python单例模式实例分析
2015/01/14 Python
用Python一键搭建Http服务器的方法
2018/06/01 Python
python实现雨滴下落到地面效果
2018/06/21 Python
python mac下安装虚拟环境的图文教程
2019/04/12 Python
python打印异常信息的两种实现方式
2019/12/24 Python
pyinstaller将含有多个py文件的python程序做成exe
2020/04/29 Python
想学画画?python满足你!
2020/12/24 Python
Python调用系统命令os.system()和os.popen()的实现
2020/12/31 Python
CSS3制作轮播图的一种方法
2019/11/11 HTML / CSS
DHC美国官网:日本通信销售第一的化妆品品牌
2017/11/12 全球购物
西班牙购买隐形眼镜、眼镜和太阳镜网站:Lentiamo.es
2020/06/11 全球购物
中国电子产品批发商/跨境电商/外贸网:Sunsky-online
2020/04/20 全球购物
酒店仓管员岗位职责
2015/04/01 职场文书
工厂门卫岗位职责
2015/04/13 职场文书
Go语言安装并操作redis的go-redis库
2022/04/14 Golang
Redis基本数据类型Zset有序集合常用操作
2022/06/01 Redis