python with语句与contextlib
参考链接:https://www.ibm.com/developerworks/cn/opensource/os-cn-pythonwith/
with语句用于异常处理,适用于存在资源访问的场合,无论在资源访问的过程中是否发生异常,都会执行必要的清理操作,释放资源,比如文件打开后自动关闭、线程中锁的自动获取和释放
要明白with语句是怎样使用的,有必要引入一些上下文管理器的相关概念
上下文管理器、上下文管理协议、运行时上下文、上下文表达式、语句体
上下文管理器和上下文管理协议是两个相互关联的定义:具体来说,上下文管理协议是指两个方法:__enter__()和__exit__(),支持该协议的对象必须实现这两个方法。而上下文管理器就是指支持上下文管理协议的对象。毫无疑问,这个对象实现了__enter__()、__exit__()两个方法。
上下文管理器对象定义with语句运行时要建立的“运行时上下文”,负责with语句中上下文的进入和退出。通常使用with语句调用上下文管理器,也可以直接调用其方法来实现。
运行时上下文:__enter__()会在语句体执行之前进入“运行时上下文”,__exit__()会在语句体执行完毕后从运行时上下文退出
上下文表达式:跟在with后面的语句,是用来返回一个上下文管理器的
语句体:with语句中包裹的部分
with语句的语法格式:
with context_expression [as target(s)]:
with-body
这里 context_expression 要返回一个上下文管理器对象,该对象并不赋值给 as 子句中的 target(s) ,如果指定了 as 子句的话,会将上下文管理器的 __enter__() 方法的返回值赋值给 target(s)。
target(s) 可以是单个变量,或者由“()”括起来的元组(不能是仅仅由“,”分隔的变量列表,必须加“()”)。
· Python 对一些内建对象进行改进,加入了对上下文管理器的支持,可以用于 with 语句中,比如可以自动关闭文件、线程锁的自动获取和释放等。假设要对一个文件进行操作,使用 with 语句可以有如下代码:
with open(r'somefileName') as somefile:
for line in somefile:
print line
# ...more code
这里使用了 with 语句,不管在处理文件过程中是否发生异常,都能保证 with 语句执行完毕后已经关闭了打开的文件句柄。如果使用传统的 try/finally 范式,则要使用类似如下代码:
somefile = open(r'somefileName')
try:
for line in somefile:
print line
# ...more code
finally:
somefile.close()
比较起来,使用 with 语句可以减少编码量。已经加入对上下文管理协议支持的还有模块 threading、decimal 等。
contextlib
我们已经知道,要让一个对象用于with语句,就必须实现上下文管理,而实现上下文管理是通过__enter__和__exit__这两个方法实现的:
class Query(object):
def __init__(self, name):
self.name = name
def __enter__(self):
print('Begin')
return self
def __exit__(self, exc_type, exc_value, traceback):
if exc_type:
print('Error')
else:
print('End')
def query(self):
with Query('Bob') as q:
q.query()
但是这样有些麻烦,Python的内建模块contextlib能让我们的实现变得更简便
from contextlib import contextmanager
class Query(object):
def __init__(self, name):
self.name = name
def query(self):
print('Query info about %s...' % self.name)
@contextmanager
def create_query(name):
print('Begin')
q = Query(name)
yield q
print('End')
with create_query('Bob') as q:
q.query()
contextlib提供的装饰器@contextmanger,这个装饰器接受一个generator,在生成器中用yield语句将想要用于with语句的变量输出出去。
加入我们想要在每次运行代码的前后都运行特定的代码,我们也可以选用@contextmanger这个装饰器实现
@contextmanager
def tag(name):
print("<%s>" % name)
yield#这个yield调用会执行with语句中的所有语句,因此with语句中的所有内容都将会被运行
print("</%s>" % name) with tag("h1"):
print("hello")
print("world")
#这段代码的执行效果是:
<h1>
hello
world
</h1>
@closing
此外,如果一个对象没有实现运行时上下文,他就不能被应用到with语句当中,我们可以使用contextlib提供的@closing装饰器将其变为上下文对象
from contextlib import closing
from urllib.request import urlopen with closing(urlopen('https://www.python.org')) as page:
for line in page:
print(line)
closing其实也是一个经过@contextmanger装饰的genterator,
@contextmanager
def closing(thing):
try:
yield thing
finally:
thing.close()
它的作用就是将任意对象变为上下文对象,并支持with语句
奇怪的是,并不是所有的对象都能够通过closing()方法变为上下文对象:(错误是Query对象没有实现close()方法)
class Query(object):
def __init__(self,name):
self.name=name
...
with closing(Query('bob')) as p:
print(p.name)
#错误信息:
bob#仍然能输出
Traceback (most recent call last):
File "c:\Users\Administrator.SC-201605202132\.vscode\extensions\ms-python.python-2019.9.34911\pythonFiles\ptvsd_launcher.py", line 43, in <module>
main(ptvsdArgs)
File "c:\Users\Administrator.SC-201605202132\.vscode\extensions\ms-python.python-2019.9.34911\pythonFiles\lib\python\ptvsd\__main__.py", line 432, in main
run()
File "c:\Users\Administrator.SC-201605202132\.vscode\extensions\ms-python.python-2019.9.34911\pythonFiles\lib\python\ptvsd\__main__.py", line 316, in run_file
runpy.run_path(target, run_name='__main__')
File "c:\users\administrator.sc-201605202132\appdata\local\programs\python\python36\Lib\runpy.py", line 263, in run_path
pkg_name=pkg_name, script_name=fname)
File "c:\users\administrator.sc-201605202132\appdata\local\programs\python\python36\Lib\runpy.py", line 96, in _run_module_code
mod_name, mod_spec, pkg_name, script_name)
File "c:\users\administrator.sc-201605202132\appdata\local\programs\python\python36\Lib\runpy.py", line 85, in _run_code
exec(code, run_globals)
File "c:\Users\Administrator.SC-201605202132\Envs\sort\app\forTest.py", line 26, in <module>
print(p.name)
File "c:\users\administrator.sc-201605202132\appdata\local\programs\python\python36\Lib\contextlib.py", line 185, in __exit__
self.thing.close()
AttributeError: 'Query' object has no attribute 'close'
PS C:\Users\Administrator.SC-201605202132\Envs\sort>
此外,contextlib还有一些其他的装饰器,供我们写出简洁的代码
python with语句与contextlib的更多相关文章
- python上下文管理器ContextLib及with语句
http://blog.csdn.net/pipisorry/article/details/50444736 with语句 with语句是从 Python 2.5 开始引入的一种与异常处理相关的功能 ...
- Python —条件语句
条件语句 Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块. 可以通过下图来简单了解条件语句的执行过程: Python程序语言指定任何非0和非空(null ...
- Python pass 语句使用示例
Python pass 语句的使用方法示例.Python pass是空语句,pass语句什么也不做,一般作为占位符或者创建占位程序,是为了保持程序结构的完整性,pass语句不会执行任何操作,比如: P ...
- Python学习教程(learning Python)--1.2.1 Python输出语句print基本使用
Python提供很多的内建(built-in)函数,使用者可以不用自己写代码就可以完成一个功能很强大的程序, 在Python里使用最多的(也许是)print函数主要用于用户输出信息. 基本用法:pri ...
- Python 条件语句
Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块. Python程序语言指定任何非0和非空(null)值为true,0 或者 null为false. Py ...
- python 循环语句 函数 模块
python循环语句 while循环语法结构 当需要语句不断的重复执行时,可以使用while循环 while expression: while_suite 语句ehile_suite会被连续不断的循 ...
- jmeter数据库,charles抓包,Python循环语句
jmeter数据库,charles抓包,Python循环语句 一.Jemeter数据库 添加jar包数据库 jemeter=>浏览 添加JDBC Connection Configuration ...
- Python import语句导入模块语法[转]
Python import语句导入模块语法 社区推荐:掘金是国内最活跃的技术社区,我们每日有优质Python开发实例分享,海量python开源库推送.来掘金,和更多懂技术的小伙伴交流. pytho ...
- python 基本语句
python 基本语句 在使用python的变量前必须给它赋值,因为python变量没有默认值. 获取用户输入值 此时需要注意:input函数的返回值为文本或字符串. 一些简单的函数 乘方 绝对值 将 ...
随机推荐
- Java生鲜电商平台-高并发核心技术订单与库存实战
Java生鲜电商平台-高并发核心技术订单与库存实战 一. 问题 一件商品只有100个库存,现在有1000或者更多的用户来购买,每个用户计划同时购买1个到几个不等商品. 如何保证库存在高并发的场景下是安 ...
- python基础—条件语句
一.Python基础 1.第一句python print('hello,world') Q: 后缀名可以任意? A: 导入模块时,如果不是.py后缀,会出错. 2.两种执行的方式: -python解 ...
- WeTest全球化服务,为使命召唤手游质量保驾护航
导读 使命召唤系列作为经典FPS游戏,以良好的表现与出色的射击手感,颠覆了玩家对传统第一人称射击的传统观念.同名手游(CODM)10月份在海外上线,仅一周内下载量就已突破一亿次,更是横扫139个国家及 ...
- 基于vue+uniapp直播项目|uni-app仿抖音/陌陌直播室
一.项目简介 uni-liveShow是一个基于vue+uni-app技术开发的集小视频/IM聊天/直播等功能于一体的微直播项目.界面仿制抖音|火山小视频/陌陌直播,支持编译到多端(H5.小程序.Ap ...
- 【JavaWeb】jQuery对Ajax的支持
jQuery对Ajax的支持 jQuery对Ajax进行封装,提供了$.ajax()方法 语法:$.ajax(options) 常用设置项 说明 url 发送请求地址 type 请求类型get|pos ...
- 【JavaScript】使用document.write输出覆盖HTML问题
您只能在 HTML 输出中使用 document.write.如果您在文档加载后使用该方法,会覆盖整个文档. 分析 HTML输出流是指当前数据形式是HTML格式的数据,这部分数据正在被导出.传输或显示 ...
- 一行代码完成 Java的 Excel 读写--easyexcel
最近我在 Github 上查找一个可以快速开发 excel 导入导出工具,偶然发现由阿里开发 easyexcel 开源项目,尝试使用后感觉这款工具挺不错的,下面分享一下我的 easyexcel 案例使 ...
- django前奏
目录 前言 web框架本质 服务器程序和应用程序 python三大主流web框架 django flask torndao Django安装配置 注意事项 命令行创建项目 app的概念 pycharm ...
- 动态链接库(Dynamic Link Library)
DLL INTRODUCTION A DLL is a library that contains code and data that can be used by more than one pr ...
- Jmeter+ant+Jenkins构建接口自动化测试时构建失败 提示:Fatal Error! 字符引用 "&#原因
Jmeter+ant+Jenkins构建接口自动化测试时构建失败 提示:Fatal Error! 字符引用 "&#原因:接口响应数据中有&#