我试图了解这些之间是否存在差异,以及可能存在的差异。
选项一:
file_obj = open('test.txt', 'r')
with file_obj as in_file:
print in_file.readlines()
选项二:
with open('test.txt', 'r') as in_file:
print in_file.readlines()
我理解使用选项一,file_obj
在with块之后处于关闭状态。
答案 0 :(得分:30)
我不知道为什么没人提到这一点,因为它是the way with
works的基础。与Python中的许多语言功能一样,with
幕后调用special methods,它们已经为内置Python对象定义,可以被用户定义的类覆盖。在with
的特定情况下(以及更常见的上下文管理器),方法为__enter__
和__exit__
。
请记住,在Python 一切都是对象 - 甚至是文字。这就是你可以做'hello'[0]
之类的事情的原因。因此,您是否直接使用open
:
with open('filename.txt') as infile:
for line in infile:
print(line)
或先用不同的名称存储它(例如分解一条长行):
the_file = open('filename' + some_var + '.txt')
with the_file as infile:
for line in infile:
print(line)
因为最终结果是the_file
,infile
和open
的返回值都指向同一个对象,而with
是什么正在调用__enter__
和__exit__
方法。内置文件对象的__exit__
方法是关闭文件的。
答案 1 :(得分:9)
这些行为相同。作为一般规则,通过将表达式赋值给同一范围内的变量,不会改变Python代码的含义。
这是相同的原因:
f = open("myfile.txt")
VS
filename = "myfile.txt"
f = open(filename)
无论是否添加别名,代码的含义都保持不变。上下文管理器比将参数传递给函数有更深层的含义,但原理是相同的:上下文管理器魔术应用于同一个对象,文件在两种情况下都会关闭。
选择其中一个的唯一原因是,如果您觉得它有助于代码清晰度或风格。
答案 2 :(得分:5)
两者之间没有区别 - 退出with块时文件关闭的方式。
您给出的第二个示例是Python 2.6及更新版本(在添加with
语法时)使用文件的典型方式。
您可以验证第一个示例是否也适用于REPL会话,如下所示:
>>> 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
所以在with
块退出后,文件将被关闭。
通常,第二个例子就是你如何做这类事情。
没有理由创建额外的变量file_obj
...在with
块结束后你可能想要用它来做任何事情你可以使用{{1因为它仍然在范围内。
in_file
答案 3 :(得分:5)
如果您只是启动Python并使用其中任何一个选项,那么如果Python的file
对象的基本实例未更改,则净效果是相同的。 (在选项一中,文件仅在file_obj
超出范围时关闭,而在选项二中的块结束时关闭,如您所观察到的那样。)
然而 与<{3}}的用例存在差异。由于file
是一个对象,您可以对其进行修改或对其进行子类化。
您也可以通过调用file(file_name)
来显示file
与其他对象一样(但没有人在Python中打开文件,除非它与with
一起),从而打开文件:< / p>
>>> 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()
更一般地说,您按照以下步骤打开和关闭一些名为the_thing
的资源(通常是文件,但可以是任何内容):
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__
您可以使用上下文管理器与open
和代码的其他元素之间编写的过程代码更轻松地更改这些子元素的流量。
从Python 2.5开始,文件对象具有__enter __和__exit__方法:
>>> 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 file
对象以这种方式使用这些方法:
__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.
可以更改这些方法以供您自己使用,以修改资源在打开或关闭时的处理方式。上下文管理器使非常容易来修改打开或关闭文件时发生的事情。
琐碎的例子:
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)
现在尝试:
>>> with Myopen('a.txt', opening='Hello', closing='Good Night') as f:
... print f.read()
...
Hello
[contents of the file 'a.txt']
Good Night
一旦控制了资源的进入和退出,就会有很多用例:
True
或False
来更改您引发的例外情况。 您可以在context manager
中阅读更多示例答案 4 :(得分:0)
即使with
或return
在内部被调用(也意味着sys.exit()
仍被调用),__exit__
仍然有效:
#!/usr/bin/env python
import sys
class MyClass:
def __enter__(self):
print("Enter")
return self
def __exit__(self, type, value, trace):
print("type: {} | value: {} | trace: {}".format(type,value,trace))
# main code:
def myfunc(msg):
with MyClass() as sample:
print(msg)
# also works if uncomment this:
# sys.exit(0)
return
myfunc("Hello")
return
版本将显示:
Enter
Hello
type: None | value: None | trace: None
exit(0)
版本将显示:
Enter
Hello
type: <class 'SystemExit'> | value: 0 | trace: <traceback object at 0x7faca83a7e00>