我试图了解这些之间是否存在差异,以及这种差异可能是什么.
方案一:
file_obj = open('test.txt', 'r')
with file_obj as in_file:
print in_file.readlines()
Run Code Online (Sandbox Code Playgroud)
方案二:
with open('test.txt', 'r') as in_file:
print in_file.readlines()
Run Code Online (Sandbox Code Playgroud)
我理解,对于Option 1,file_obj在with块之后处于关闭状态.
Two*_*ist 32
我不知道为什么还没有人提到这一点,因为这是工作方式with的基础.与Python中的许多语言功能一样,with后台调用特殊方法,这些方法已经为内置Python对象定义,并且可以被用户定义的类覆盖.在with特定情况下(以及更普遍的上下文管理器),方法是__enter__和__exit__.
请记住,在Python中,一切都是对象 - 甚至是文字.这就是为什么你可以做的事情'hello'[0].因此,您是否直接使用文件对象并不重要open:
with open('filename.txt') as infile:
for line in infile:
print(line)
Run Code Online (Sandbox Code Playgroud)
或者先用不同的名称存储它(例如分解一条长行):
the_file = open('filename' + some_var + '.txt')
with the_file as infile:
for line in infile:
print(line)
Run Code Online (Sandbox Code Playgroud)
因为最终的结果是the_file,infile和返回值open都指向同一个对象,这就是with被调用__enter__和__exit__方法上.内置文件对象的__exit__方法是关闭文件.
这些表现相同.作为一般规则,通过将表达式分配给同一范围内的变量,不会更改Python代码的含义.
这与这些相同的原因相同:
f = open("myfile.txt")
Run Code Online (Sandbox Code Playgroud)
VS
filename = "myfile.txt"
f = open(filename)
Run Code Online (Sandbox Code Playgroud)
无论您是否添加别名,代码的含义都保持不变.上下文管理器比将参数传递给函数具有更深层的含义,但原理是相同的:上下文管理器魔术应用于同一个对象,并且文件在两种情况下都被关闭.
选择一个而不是另一个的唯一原因是,如果您觉得它有助于代码清晰度或风格.
两者之间没有区别 - 退出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
Run Code Online (Sandbox Code Playgroud)
因此,在with块退出后,文件将关闭.
通常,第二个例子是你如何做这种事情.
没有理由创建那个额外的变量file_obj......在with你可以使用的块结束之后你可能想要用它做什么in_file,因为它仍然在范围内.
>>> in_file
<closed file 'test.txt', mode 'r' at 0x03DC5020>
Run Code Online (Sandbox Code Playgroud)
如果您只是启动Python并使用其中任何一个选项,那么如果file不更改Python 对象的基本实例,则净效果是相同的.(在选项一中,文件仅在file_obj超出范围时关闭,而在选项二中的块结尾处才会关闭,如您已经观察到的那样.)
有可能是有差异与使用情况上下文管理不过.由于file是一个对象,您可以对其进行修改或子类化.
您也可以通过调用file(file_name)显示file与其他对象一样的方式来打开文件(但没有人在Python中以这种方式打开文件,除非它与之一起with):
>>> 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()
Run Code Online (Sandbox Code Playgroud)
更一般地说,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__
Run Code Online (Sandbox Code Playgroud)
您可以使用上下文管理器与代码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>
Run Code Online (Sandbox Code Playgroud)
默认的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.
Run Code Online (Sandbox Code Playgroud)
可以更改这些方法以供您自己使用,以修改资源在打开或关闭时的处理方式.上下文管理器可以很容易地修改打开或关闭文件时发生的情况.
琐碎的例子:
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)
Run Code Online (Sandbox Code Playgroud)
现在尝试:
>>> with Myopen('a.txt', opening='Hello', closing='Good Night') as f:
... print f.read()
...
Hello
[contents of the file 'a.txt']
Good Night
Run Code Online (Sandbox Code Playgroud)
一旦控制了资源的进入和退出,就会有很多用例:
True或False从__exit__方法更改引发的异常.| 归档时间: |
|
| 查看次数: |
22643 次 |
| 最近记录: |