python关键字详解_Python 中的关键字with详解

在 Python 2.5 中,with关键字被加入。它将常用的 try ... except ... finally ...模式很方便的被复用。看一个最经典的例子:

with open('file.txt') as f:

content = f.read()

在这段代码中,无论with中的代码块在执行的过程中发生任何情况,文件最终都会被关闭。如果代码块在执行的过程中发生了一个异常,那么在这个异常被抛出前,程序会先将被打开的文件关闭。

再看另外一个例子。

在发起一个数据库事务请求的时候,经常会用类似这样的代码:

db.begin()

try:

# do some actions

except:

db.rollback()

raise

finally:

db.commit()

如果将发起事务请求的操作变成可以支持with关键字的,那么用像这样的代码就可以了:

with transaction(db):

# do some actions

下面,详细的说明一下with的执行过程,并用两种常用的方式实现上面的代码。

with 的一般执行过程

一段基本的with表达式,其结构是这样的:

with EXPR as VAR:

BLOCK

其中:EXPR可以是任意表达式;as VAR是可选的。其一般的执行过程是这样的:

计算EXPR,并获取一个上下文管理器。

上下文管理器的__exit()__方法被保存起来用于之后的调用。

调用上下文管理器的__enter()__方法。

如果with表达式包含as VAR,那么EXPR的返回值被赋值给VAR。

执行BLOCK中的表达式。

调用上下文管理器的__exit()__方法。如果BLOCK的执行过程中发生了一个异常导致程序退出,那么异常的type、value和traceback(即sys.exc_info()的返回值)将作为参数传递给__exit()__方法。否则,将传递三个None。

将这个过程用代码表示,是这样的:

mgr = (EXPR)

exit = type(mgr).__exit__ # 这里没有执行

value = type(mgr).__enter__(mgr)

exc = True

try:

try:

VAR = value # 如果有 as VAR

BLOCK

except:

exc = False

if not exit(mgr, *sys.exc_info()):

raise

finally:

if exc:

exit(mgr, None, None, None)

这个过程有几个细节:

如果上下文管理器中没有__enter()__或者__exit()__中的任意一个方法,那么解释器会抛出一个AttributeError。

在BLOCK中发生异常后,如果__exit()__方法返回一个可被看成是True的值,那么这个异常就不会被抛出,后面的代码会继续执行。

接下来,用两种方法来实现上面来实现上面的过程的吧。

实现上下文管理器类

第一种方法是实现一个类,其含有一个实例属性db和上下文管理器所需要的方法__enter()__和__exit()__。

class transaction(object):

def __init__(self, db):

self.db = db

def __enter__(self):

self.db.begin()

def __exit__(self, type, value, traceback):

if type is None:

db.commit()

else:

db.rollback()

了解with的执行过程后,这个实现方式是很容易理解的。下面介绍的实现方式,其原理理解起来要复杂很多。

使用生成器装饰器

在Python的标准库中,有一个装饰器可以通过生成器获取上下文管理器。使用生成器装饰器的实现过程如下:

from contextlib import contextmanager

@contextmanager

def transaction(db):

db.begin()

try:

yield db

except:

db.rollback()

raise

else:

db.commit()

第一眼上看去,这种实现方式更为简单,但是其机制更为复杂。看一下其执行过程吧:

Python解释器识别到yield关键字后,def会创建一个生成器函数替代常规的函数(在类定义之外我喜欢用函数代替方法)。

装饰器contextmanager被调用并返回一个帮助方法,这个帮助函数在被调用后会生成一个GeneratorContextManager实例。最终with表达式中的EXPR调用的是由contentmanager装饰器返回的帮助函数。

with表达式调用transaction(db),实际上是调用帮助函数。帮助函数调用生成器函数,生成器函数创建一个生成器。

帮助函数将这个生成器传递给GeneratorContextManager,并创建一个GeneratorContextManager的实例对象作为上下文管理器。

with表达式调用实例对象的上下文管理器的__enter()__方法。

__enter()__方法中会调用这个生成器的next()方法。这时候,生成器方法会执行到yield db处停止,并将db作为next()的返回值。如果有as VAR,那么它将会被赋值给VAR。

with中的BLOCK被执行。

BLOCK执行结束后,调用上下文管理器的__exit()__方法。__exit()__方法会再次调用生成器的next()方法。如果发生StopIteration异常,则pass。

如果没有发生异常生成器方法将会执行db.commit(),否则会执行db.rollback()。

再次看看上述过程的代码大致实现:

def contextmanager(func):

def helper(*args, **kwargs):

return GeneratorContextManager(func(*args, **kwargs))

return helper

class GeneratorContextManager(object):

def __init__(self, gen):

self.gen = gen

def __enter__(self):

try:

return self.gen.next()

except StopIteration:

raise RuntimeError("generator didn't yield")

def __exit__(self, type, value, traceback):

if type is None:

try:

self.gen.next()

except StopIteration:

pass

else:

raise RuntimeError("generator didn't stop")

else:

try:

self.gen.throw(type, value, traceback)

raise RuntimeError("generator didn't stop after throw()")

except StopIteration:

return True

except:

if sys.exc_info()[1] is not value:

raise

总结

Python的with表达式包含了很多Python特性。花点时间吃透with是一件非常值得的事情。

一些其他的例子

锁:

@contextmanager

def locked(lock):

lock.acquired()

try:

yield

finally:

lock.release()

标准输出重定向:

@contextmanager

def stdout_redirect(new_stdout):

old_stdout = sys.stdout

sys.stdout = new_stdout

try:

yield

finally:

sys.stdout = old_stdout

with open("file.txt", "w") as f:

with stdout_redirect(f):

print "hello world"

引用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/355699.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python interactive window_如果PySide应用程序是从IPython interactive cons运行的,上下文菜单就会消失...

在下面给出的最小示例中,上下文菜单(右键单击gui的白色部分)仅短暂显示,然后消失。如果应用程序是从IPython(0.13.1)控制台启动的,则会出现这种情况。当从shell正常启动时,它可以正常工作。在import sysfrom PySide import QtGui,…

基准测试:Java 8 Lambda和流如何使您的代码慢5倍

与长期的实现相比,Java 8 lambda和流的性能如何? Lambda表达式和流在Java 8中受到了热烈的欢迎。这些是迄今为止很激动人心的功能,很长一段时间以来,它们就已经应用到Java中了。 新的语言功能使我们可以在代码中采用更具功能性的…

ssm框架逻辑删除mysql_MybatisPlus--CRUD接口及主键增长策略、自动填充、乐观锁更新数据...

目录一、insert1、插入操作2、主键策略二、update1、根据Id更新操作2、自动填充3、乐观锁三、select1、根据id查询记录2、通过多个id批量查询3、简单的条件查询4、分页四、delete1、根据id删除记录2、批量删除3、简单的条件查询删除4、逻辑删除一、insert1、插入操作RunWith(Sp…

python对英语的要求_学python需要英语基础吗

在很多人的眼里,学习编程需要英语基础,因为程序代码全是英文字母,如果没有英语基础可能很难学懂编程。程序代码是英文确实没有错,但是也不是必须得懂英语,因为计算机程序有自己语言,并不是我们生活中的英语…

mysql5.6 优点_MySQL5.6复制:GTID的优点和限制(第一部分)_MySQL

bitsCN.com全局事务标示符(Global Transactions Identifier)是MySQL 5.6复制的一个新特性。它为维护特定的复制拓扑结构下服务器的DBA们大幅度改善他们的工作状况提供了多种可能性。然而,你还应该明白当前实现的一些局限。本博文是专门对在生产环境中启用GTID到底意…

python找不到csv文件_Python如何读取csv文件

逗号分隔值(Comma-Separated Values,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本)。纯文本意味着该文件是一个字符序列&…

jsf 自定义属性_必填字段的自定义JSF验证器

jsf 自定义属性实现EditableValueHolder接口的JSF组件具有两个属性“ required”和“ requiredMessage” –一个标志,指示用户需要输入/选择非空值,以及一个用于验证消息的文本。 我们可以使用它,但是它不够灵活,我们不能直接在视…

Python那些事

Python这几年很火,在这里我用问答的方式来总结一下使用python的一些常见问题,对自己是个总结,也希望对有同样问题的朋友有帮助。Q:Python为什么流行?A:Python是一个比较方便的跨平台脚本语言。对于像我这种…

python cv2模块imshow_Python-OpenCV:cv2.imread(),cv2.imshow(),cv2.imwrite()

一、需要工具本机使用python 2.7.10下调试代码均通过,一下学习需要有一定的代码阅读能力,一下学习只介绍函数方法:Python 作为一种高效简洁的直译式语言非常适合我们用来解决日常工作的问题。而且它简单易学,初学者几个小时就可以…

python程序设计课程设计_《Python程序设计》教学大纲.doc

PAGE 理论课程教学大纲 《Python程序设计》教学大纲 课程编号: 总 学 时:64(其中,讲课:32;实验:32) 学 分:3 实践教学:0周 修读专业:地理信息系统…

2016年将是Java终于拥有窗口函数的那一年!

你没听错。 到目前为止,出色的窗口功能是SQL独有的功能。 即使是复杂的函数式编程语言似乎也缺少这种漂亮的功能(如果我记错了,请纠正我,Haskell伙计们)。 我们撰写了许多有关窗口函数的博客文章,并在诸如…

LINQ to Entities 不识别方法“System.String ToString() 的解决方法

今天在做一个页面的时候出现了LINQ to Entities 不识别方法“System.String ToString()”的错误&#xff0c;对于源码IQueryable<SelectListItem> items roleInfoServer.Get(r > true).Select(r > new SelectListItem() { Value r.Id.ToString(), Text r.RoleNa…

android 仿京东地址选择_Android 开发:仿美团地址选择

最近做了这个功能&#xff0c;分享一下&#xff0c;用的是百度地图api&#xff0c;和美团外卖的地址选择界面差不多&#xff0c;也就是可以搜索或者滑动地图展示地址列表给用户选择&#xff0c;看下效果图先。文章重点展示地图并定位到“我”的位置 滑动地图获取周边poi(逆地理…

简单回顾在杭州7年

回顾2010年回到浙江杭州&#xff0c;从一开始做.net到后来转到As3网页游戏开发&#xff0c;后又搞起android&#xff0c;那时候就立志想做一款有关于bible的游戏&#xff0c;2010年进入一家创业公司&#xff0c;叫追梦&#xff0c;是追求梦想的开始&#xff0c;在那接触火山和A…

ps还原上一步快捷键_ps还原上一步快捷键_photoshop恢复上一步操作的快捷键是什么...

满意答案simonsinxer推荐于 2017.09.01采纳率&#xff1a;53% 等级&#xff1a;11已帮助&#xff1a;63469人还原/重做前一步操作 【Ctrl】【Z】其他一些快捷键&#xff1a;还原两步以上操作 【Ctrl】【Alt】【Z】重做两步以上操作 【Ctrl】【Shift】【Z】剪切选取的图像或路…

python中排序从小到大_从Python看排序:冒泡排序

冒泡排序在排序算法中是最简单的一种&#xff0c;它通过多次遍历列表&#xff0c;将最大的元素冒泡到列表的头部或尾部。我们通过对四张扑克牌&#xff08;花色相同&#xff09;以从小到大的方式进行排序来演示该算法的工作原理。首先将扑克牌面朝上放在桌上&#xff0c;如下图…

Shell else if mysql_Shell if else语句(详解版)

和其它编程语言类似&#xff0c;Shell 也支持选择结构&#xff0c;并且有两种形式&#xff0c;分别是 if else 语句和 case in 语句。本节我们先介绍 if else 语句&#xff0c;case in 语句将会在《Shell case in》中介绍。如果你已经熟悉了C语言、Java、JavaScript 等其它编程…

【Java并发编程】:使用synchronized获取互斥锁

在并发编程中&#xff0c;多线程同时并发访问的资源叫做临界资源&#xff0c;当多个线程同时访问对象并要求操作相同资源时&#xff0c;分割了原子操作就有可能出现数据的不一致或数据不完整的情况&#xff0c;为避免这种情况的发生&#xff0c;我们会采取同步机制&#xff0c;…

WildFly Swarm –将Java EE应用程序部署为独立的Jar

WildFly Swarm为将Java EE应用程序部署为独立的Jar文件提供了一种简单的解决方案。 这使得部署应用程序特别是REST或Web服务非常容易。 Swarm在这方面与Spring Boot非常相似&#xff0c;因为它可以快速开发Web&#xff08;.War&#xff09;应用程序&#xff0c;然后将其部署为独…

c语言三个数从小到大排序/输出_我的c语言笔记(三)

int表达式这个表达式存在的目的在于将表达式转为整数。比如&#xff1a;float a9999.9999&#xff1b;int b;b(int)(a/1000);就可以得到9啦&#xff0c;别忘了套上固定格式哦&#xff5e;然后我们接下来一起来做一道很重要的题哦&#xff0c;反复练习&#xff0c;可以顺利拿下同…