为什么上下文在with语句后仍然存在?

7 投票
5 回答
954 浏览
提问于 2025-04-16 11:57

我想知道为什么用 with 语句或者在一个代码块中打开的文件对象,在退出后仍然可以使用。那种 <closed file> 的对象会被清理掉吗?

>>> with open('test.txt','w') as f:
...     f.write('test')
...
>>> f
<closed file 'test.txt', mode 'w' at 0x00E014F0>
>>> f.close()


>>> if True:
...     fal = open('demo.txt','w')
...     fal.write('stuff')
...     fal.close()
...
>>> fal
<closed file 'demo.txt', mode 'w' at 0x00E015A0>

5 个回答

2

withif 并不会创建新的作用域,局部变量只会在函数、类和模块内部被创建。想了解更多,可以查看这个链接:在 if 语句中声明的 Python 变量的作用域是什么?

4

这个名字会一直有效,直到你离开这个范围。

如果你想让这个对象被清理掉,可以给这个名字赋一个不同的值,比如:

f = None

这样做并不会关闭文件!

养成把程序结构化成函数(可能还会有类)的习惯是个好主意,这样可以让范围更小,更易于阅读,同时也能让那些没有名字指向的对象(也就是没有任何名字在范围内指向这个对象)可以被垃圾回收。

不过,通常在使用提示符的时候,这并不是个问题哦 :)

16

在Python中,新的作用域(也叫命名空间)只会在模块、类和函数中创建,而不会在其他语句中创建,特别是像withif这样的代码块。也就是说,在withfor语句的内部定义的变量,实际上是绑定在最内层的外部作用域中,这个外部作用域在你使用的交互式解释器中就是顶层作用域。只要这个作用域有效,变量就会一直存在,直到你明确地将它们从作用域中删除(比如使用del,像del fal那样)。

对象只有在不再被引用时才能被清理。不过,实际清理对象的时机是不确定的。Python使用垃圾回收来管理内存,并没有强制采用特定的策略。在CPython中(这是Python的一种实现,使用引用计数),一旦最后一个引用超出作用域,对象就会立即被清理。而像PyPy或Jython这样的其他实现则使用更先进的垃圾收集器,可以在任意时刻清理那些没有被引用的对象。

这意味着,在你的例子中,绑定到ffal的对象基本上是不会被清理的,因为交互式解释器的顶层作用域只要解释器在运行就会一直存在。不过,实际上这并不是个问题,因为这些对象仍然会被正确关闭,并且不再占用任何文件资源,只占用一些内存而已。

撰写回答