这是什么(在声明中)?它是变量还是别的什么?

时间:2016-04-08 15:03:29

标签: python python-3.x

我正在使用Python 3.x.有人可以向我解释下面代码块中的file是什么?

with open(filename, "a") as file:
    file.write("Hello world")
    print(file) #I added this line to try to understand what 'file' is.

当我运行上面的代码时,print(file)产生了这个:

<_io.TextIOWrapper name='Class_A.txt' mode='a' encoding='cp1252'>

我不明白这一点。我可以看到它与with语句有关,但它看起来并不像变量。

那么file是什么?它是变量还是别的什么?如果它是变量,它是什么数据类型?

3 个答案:

答案 0 :(得分:4)

是的,file是一个变量,引用open()返回的上下文管理器生成的任何内容。它碰巧是同一个对象。换句话说,file引用文件对象。

你也可以这样做,效果如下:

file = open(filename, "a")
try:
    file.write("Hello world")
finally:
    file.close()

因此文件会自动关闭。这是因为文件对象是上下文管理器;他们支持context manager protocol。从技术上讲,with context_manager as <name>目标变量绑定到context_manager.__enter__()的返回值,但文件对象从该方法返回自身,file.__exit__()方法关闭文件。请参阅with compound statement documentation

现在,当您打印一个没有字符串表示的对象时,它将使用repr()函数打印:

>>> repr(open('/dev/null'))
"<_io.TextIOWrapper name='/dev/null' mode='r' encoding='UTF-8'>"
>>> print(repr(open('/dev/null')))
<_io.TextIOWrapper name='/dev/null' mode='r' encoding='UTF-8'>

所以是的,这只是另一个对象,一个具有自定义,有用的表示。文件对象实现object.__repr__() hook以产生这个:

>>> open('/dev/null').__repr__()
"<_io.TextIOWrapper name='/dev/null' mode='r' encoding='UTF-8'>"

文件对象的名称在这里也可能令人困惑。这是因为Python中的文件对象是io module定义的一系列对象的一部分;一个TextIOWrapper object包装一个缓冲区(这里是一个BufferedReader,它将以FileIO object的形式包装原始的二进制文件对象:

>>> devnull = open('/dev/null', 'r')
>>> devnull
<_io.TextIOWrapper name='/dev/null' mode='r' encoding='UTF-8'>
>>> devnull.buffer
<_io.BufferedReader name='/dev/null'>
>>> devnull.buffer.raw
<_io.FileIO name='/dev/null' mode='rb' closefd=True>

这些只是您通常不必担心的技术细节。每个对象执行一个特定的功能,需要进行更高级I / O争用的人可以混合和匹配这些功能。

答案 1 :(得分:4)

当对象没有自己的__str__file时,它就是对象的文本表示形式。 {{1}}是一个变量,指向在with语句中创建的对象。

答案 2 :(得分:3)

这是open(filename, "a")上下文管理器调用返回的对象。 _io.TextIOWrapper是一个file-like object,您可以执行诸如读取,写入,搜索和关闭之类的操作。

执行此操作时:

with thing1 as thing2: 

调用方法thing1.__enter__,并将其返回的内容分配给变量/名称thing2

所以是的,在您的示例中file确实是一个已分配给with上下文管理器返回的任何对象的变量。在这种情况下,它是_io.TextIOWrapper对象。这就是你这样做的原因:

print(file)

你得到:

<_io.TextIOWrapper name='Class_A.txt' mode='a' encoding='cp1252'>

...这只是那种对象的字符串表示。

您可以通过这种方式手动获取相同的对象:

file = open(filename, "a").__enter__()
print(file) # same file-like object you were getting before
file.write('a line') # do stuff with it
file.close() # close it

请注意,open(filename, "a").__enter__()返回的对象与您从open(filename, "a")获得的对象相同。这是因为__enter__()对象的_io.TextIOWrapper方法只返回self。但是,其他对象并非总是如此。

如果您发现所有这些令人困惑,我建议您阅读更多有关with statement的信息。