【转】 Python3 With as 语句如何理解

《 python 标准库 》上这么一句话:

[python] view plain copy

  1. with open(‘filename‘, ‘wt‘) as f:
  2. f.write(‘hello, world!‘)

我不明白为什么这样写,下面这篇文章对此做出了解释

原文地址:http://python.42qu.com/11155501

With语句是什么?

Python’s with statement provides a very convenient way of dealing with the situation where you have to do a setup and teardown to make something happen. A very good example for this is the situation where you want to gain a handler to a file, read data from the file and the close the file handler.
有一些任务,可能事先需要设置,事后做清理工作。对于这种场景,Python的with语句提供了一种非常方便的处理方式。一个很好的例子是文件处理,你需要获取一个文件句柄,从文件中读取数据,然后关闭文件句柄。

Without the with statement, one would write something along the lines of:
如果不用with语句,代码如下:


1

2

3

file = open("/tmp/foo.txt")

data = file.read()

file.close()

There are two annoying things here. First, you end up forgetting to close the file handler. The second is how to handle exceptions that may occur once the file handler has been obtained. One could write something like this to get around this:
这里有两个问题。一是可能忘记关闭文件句柄;二是文件读取数据发生异常,没有进行任何处理。下面是处理异常的加强版本:


1

2

3

4

5

file = open("/tmp/foo.txt")

try:

    data = file.read()

finally:

    file.close()

While this works well, it is unnecessarily verbose. This is where with is useful. The good thing about with apart from the better syntax is that it is very good handling exceptions. The above code would look like this, when using with:
虽然这段代码运行良好,但是太冗长了。这时候就是with一展身手的时候了。除了有更优雅的语法,with还可以很好的处理上下文环境产生的异常。下面是with版本的代码:


1

2

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

    data = file.read()

with如何工作?

while this might look like magic, the way Python handles with is more clever than magic. The basic idea is that the statement after with has to evaluate an object that responds to an __enter__() as well as an __exit__() function.
这看起来充满魔法,但不仅仅是魔法,Python对with的处理还很聪明。基本思想是with所求值的对象必须有一个__enter__()方法,一个__exit__()方法。

After the statement that follows with is evaluated, the __enter__() function on the resulting object is called. The value returned by this function is assigned to the variable following as. After every statement in the block is evaluated, the __exit__() function is called.
紧跟with后面的语句被求值后,返回对象的__enter__()方法被调用,这个方法的返回值将被赋值给as后面的变量。当with后面的代码块全部被执行完之后,将调用前面返回对象的__exit__()方法。

This can be demonstrated with the following example:
下面例子可以具体说明with如何工作:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

#!/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

When executed, this will result in:
运行代码,输出如下


1

2

3

4

bash-3.2$
.
/with_example01.py

In
__enter__()

sample:
Foo

In
__exit__()

As you can see,
The __enter__() function is executed
The value returned by it - in this case "Foo" is assigned to sample
The body of the block is executed, thereby printing the value of sample ie. "Foo"
The __exit__() function is called.
What makes with really powerful is the fact that it can handle exceptions. You would have noticed that the __exit__() function for Sample takes three arguments - val, type and trace. These are useful in exception handling. Let’s see how this works by modifying the above example.
正如你看到的,
1. __enter__()方法被执行
2. __enter__()方法返回的值 - 这个例子中是"Foo",赋值给变量‘sample‘
3. 执行代码块,打印变量"sample"的值为 "Foo"
4. __exit__()方法被调用
with真正强大之处是它可以处理异常。可能你已经注意到Sample类的__exit__方法有三个参数- val, type 和 trace。 这些参数在异常处理中相当有用。我们来改一下代码,看看具体如何工作的。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

#!/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()

Notice how in this example, instead of get_sample(), with takes Sample(). It does not matter, as long as the statement that follows with evaluates to an object that has an __enter__() and __exit__() functions. In this case, Sample()’s __enter__() returns the newly created instance of Sample and that is what gets passed to sample.
这个例子中,with后面的get_sample()变成了Sample()。这没有任何关系,只要紧跟with后面的语句所返回的对象有__enter__()和__exit__()方法即可。此例中,Sample()的__enter__()方法返回新创建的Sample对象,并赋值给变量sample。

When executed:
代码执行后:


1

2

3

4

5

6

7

8

9

10

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

Essentially, if there are exceptions being thrown from anywhere inside the block, the __exit__() function for the object is called. As you can see, the type, value and the stack trace associated with the exception thrown is passed to this function. In this case, you can see that there was a ZeroDivisionError exception being thrown. People implementing libraries can write code that clean up resources, close files etc. in their __exit__() functions.
实际上,在with后面的代码块抛出任何异常时,__exit__()方法被执行。正如例子所示,异常抛出时,与之关联的type,value和stack trace传给__exit__()方法,因此抛出的ZeroDivisionError异常被打印出来了。开发库时,清理资源,关闭文件等等操作,都可以放在__exit__方法当中。

Thus, Python’s with is a nifty construct that makes code a little less verbose and makes cleaning up during exceptions a bit easier.
因此,Python的with语句是提供一个有效的机制,让代码更简练,同时在异常产生时,清理工作更简单。

I have put the code examples given here on Github.
示例代码可以在Github上面找到。

译注:本文原文见Understanding Python‘s "With" Statement

想要获取更多的Java架构知识讲解的同学,可以扫描二维码

原文地址:https://www.cnblogs.com/maibaodexiaoer/p/8590002.html

时间: 2024-10-18 23:26:38

【转】 Python3 With as 语句如何理解的相关文章

python3之if语句

获得更多资料欢迎进入我的网站或者 csdn或者博客园 本节主要介绍pythonif条件语句,以及用法.下面附有之前的文章: python3入门之赋值语句介绍 python3入门之print,import,input介绍 python入门之字典 python入门之字符串 python入门之列表和元组 python入门之软件安装 语句快介绍 语句快并非一种语句,是通过缩进形成的语句集合: 可以使用的缩进符:TAb建(相当于四个空格),4个空格,8个空格,可以成倍增加形成嵌套语句快: 一般来说使用四个

java基础-printf()语句的理解

对print和println的理解很简单,今天突然接触到printf(),有点懵,整理了下也帮自己理一理 printf是格式化输出的形式 下在举个例子: package other; public class TestPrint { //声明打印测试类 public static void main(String[] args) { //主方法 int i = 4; //声明int类型i double j = 5; //声明double类型j System.out.print("用print输出

Python3基础 else 语句 与try-except配合

镇场诗: 诚听如来语,顿舍世间名与利.愿做地藏徒,广演是经阎浮提. 愿尽吾所学,成就一良心博客.愿诸后来人,重现智慧清净体.------------------------------------------ex1: code: #如果没出错,else语句就执行 try : raise OSError('手动指明原因') except OSError as reason: print('yichang',str(reason)) else : print('程序无异常') finally: pr

JavaScript中with语句的理解

with语句的作用是暂时改变作用域链.减少的重复输入. 其语法结构为: Js代码 with(object){ //statements } 举一个实际例子吧: Js代码 with(document.forms[0]){ name.value = "lee king"; address.value = "Peking"; zipcode.value = "10000"; } 与之对应的传统的写法是: Js代码 document.forms[0].n

深入浅析JavaScript中with语句的理解

JavaScript 有个 with 关键字, with 语句的原本用意是为逐级的对象访问提供命名空间式的速写方式. 也就是在指定的代码区域, 直接通过节点名称调用对象. with语句的作用是暂时改变作用域链.减少的重复输入. 其语法结构为: with(object){ //statements } 举一个实际例子吧: with(document.forms[]){ name.value = "lee king"; address.value = "Peking";

【python3】修饰器简单理解

修饰器 修饰器干嘛的,有什么作用 比如说A现在已经写好了一个项目,但是现在B接管了这个项目,B需要对项目中的某个函数进行修改,一个一个修改然后复制,粘贴?这时候修饰器就开始大显身手了.修饰器可以避免许多重复的动作.用@+修饰函数放在待修饰的函数头上就可以实现优化函数的功能 修饰器的理解 原函数没有参数 修饰器可以看作是一个接收函数的函数,内部再定义局部函数用来修饰传进来的函数参数 def makebold(fn): def wrapped(): return "<b>" +

[IT学习]Learn Python the Hard Way (Using Python 3)笨办法学Python3版本

黑客余弦先生在知道创宇的知道创宇研发技能表v3.1中提到了入门Python的一本好书<Learn Python the Hard Way(英文版链接)>.其中的代码全部是2.7版本. 如果你觉得英文版看着累,当当网有中文版,也有电子版可以选择. 我试着将其中的代码更新到Python 3.同时附上一些自己的初学体会,希望会对你有帮助. 中文版有人把书名翻译为<笨办法学python>,其实我觉得叫做<学Python,不走寻常路>更有意思些. 作者的意思你可以在序言中详细了解

编译原理的理解

编译原理内容包括语言和文法.词法分析.语法分析.语法制导翻译.中间代码生成.存储管理.代码优化和目标代码生成.大一点的应用可以做到一定的技术先进性,从而让你在本行业站稳脚跟:分析和分解用户输入的SQL语句,理解是否有害和是否有SQL注入等.如果不学,对于不是不是本行业的人来说就没损失,如果是本行业的专业人士,不学只会令自己的编译理解更慢.

python2 与 python3的区别总结

python2 与 python3的区别总结 几乎所有的Python 2程序都需要一些修改才能正常地运行在Python 3的环境下.为了简化这个转换过程,Python 3自带了一个叫做2to3的实用脚本(Utility Script),这个脚本会将你的Python 2程序源文件作为输入,然后自动将其转换到Python 3的形式. 案例研究:将chardet移植到Python 3(porting chardet to Python 3)描述了如何运行这个脚本,然后展示了一些它不能自动修复的情况.这