Understanding the Python 'with' statement
我试着去理解这两者之间是否有区别,以及区别可能是什么。
选项一:
1 2 3 4 | file_obj = open('test.txt', 'r') with file_obj as in_file: print in_file.readlines() |
选项二:
1 2 | with open('test.txt', 'r') as in_file: print in_file.readlines() |
号
我理解,对于选项1,
我不知道为什么还没有人提到这一点,因为这是
记住,在Python中,一切都是一个对象——甚至是文本。这就是为什么你可以做像
1 2 3 | with open('filename.txt') as infile: for line in infile: print(line) |
或者先用不同的名称存储它(例如,分解一条长线):
1 2 3 4 | the_file = open('filename' + some_var + '.txt') with the_file as infile: for line in infile: print(line) |
。
因为最终的结果是
它们的行为相同。作为一般规则,不能通过将表达式赋给同一范围内的变量来改变python代码的含义。
这与它们相同的原因相同:
1 | f = open("myfile.txt") |
VS
1 2 | filename ="myfile.txt" f = open(filename) |
号
无论是否添加别名,代码的含义都保持不变。上下文管理器的含义比将参数传递给函数要深,但原理是相同的:上下文管理器的魔力应用于同一对象,并且在这两种情况下文件都会关闭。
选择一个而不是另一个的唯一原因是,如果您觉得它有助于代码的清晰性或风格。
如果您只是启动python并使用这些选项中的任何一个,那么如果不更改python的
但是,与使用上下文管理器的用例可能存在差异。由于
您也可以通过调用
1 2 3 4 5 6 7 8 9 | >>> f=open('a.txt') >>> f <open file 'a.txt', mode 'r' at 0x1064b5ae0> >>> f.close() >>> f=file('a.txt') >>> f <open file 'a.txt', mode 'r' at 0x1064b5b70> >>> f.close() |
更一般地说,打开和关闭名为
1 2 3 4 5 6 | set up the_thing # resource specific, open, or call the obj try # generically __enter__ yield pieces from the_thing except react if the_thing is broken finally, put the_thing away # generically __exit__ |
号
您可以使用上下文管理器和在
从python 2.5开始,文件对象有enter和exit方法:
1 2 3 4 5 | >>> f=open('a.txt') >>> f.__enter__ <built-in method __enter__ of file object at 0x10f836780> >>> f.__exit__ <built-in method __exit__ of file object at 0x10f836780> |
默认的python
1 2 3 4 5 | __init__(...) # performs initialization desired __enter__() -> self # in the case of `file()` return an open file handle __exit__(*excinfo) -> None. # in the case of `file()` closes the file. |
。
这些方法可以更改以供您自己使用,以修改打开或关闭资源时如何处理该资源。上下文管理器使得修改打开或关闭文件时所发生的事情变得非常容易。
简单的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class Myopen(object): def __init__(self, fn, opening='', closing='', mode='r', buffering=-1): # set up the_thing if opening: print(opening) self.closing=closing self.f=open(fn, mode, buffering) def __enter__(self): # set up the_thing # could lock the resource here return self.f def __exit__(self, exc_type, exc_value, traceback): # put the_thing away # unlock, or whatever context applicable put away the_thing requires self.f.close() if self.closing: print(self.closing) |
现在试试看:
1 2 3 4 5 6 | >>> with Myopen('a.txt', opening='Hello', closing='Good Night') as f: ... print f.read() ... Hello [contents of the file 'a.txt'] Good Night |
。
一旦您控制了资源的进入和退出,就会出现许多用例:
您可以在PEP 343中阅读更多示例。
这两种方法之间没有区别—当您退出WITH块时,关闭文件的方式也是一样的。
您给出的第二个示例是在python 2.6和更新版本(添加
您可以验证第一个示例是否也适用于这样的repl会话:
1 2 3 4 5 6 7 8 | >>> file_obj = open('test.txt', 'r') >>> file_obj.closed False >>> with file_obj as in_file: ... print in_file.readlines() <Output> >>> file_obj.closed True |
因此,在
不过,通常情况下,第二个例子是如何做这种事情。
没有理由创建额外的变量
1 2 | >>> in_file <closed file 'test.txt', mode 'r' at 0x03DC5020> |
。