Python 读写文件时不用 with 也不关闭文件,这样的风格好吗?

2021-03-27 12:13:58 +08:00
 zictos

读文件:

text = open('test.txt', 'r', encoding='utf-8').read()

写文件:

open('test.txt', 'w', encoding='utf-8').write('123')

遍历文件:

for i in open('test.txt', 'r', encoding='utf-8'):
    print(i)

.
.

发现有时候只是临时读一下文件的话这样方便不少。

如果打开文件,但没有把文件对象赋值到变量的话是不需要关闭文件的
比如输入下面一行代码的时候去删除 test.txt 文件时无法删除,提示被占用

f = open('test.txt', 'r', encoding='utf-8')  

但实际上并不需要输入 f.close(),比如直接给 f 赋值成别的数据类型 f=1,再去删除文件就不会提示占用了

f = 1  
4872 次点击
所在节点    Python
39 条回复
ClericPy
2021-03-27 12:19:59 +08:00
Explicit is better than implicit.
learningman
2021-03-27 12:21:20 +08:00
都有上下文管理器这么好用的东西了,你还嫌麻烦。。。
要不再封装成一个函数,传入文件名返回值,内部做好处理。
AndyAO
2021-03-27 12:22:21 +08:00
临时读一下文件没必要关闭,就那点资源根本就没必要释放
v2sir
2021-03-27 12:22:46 +08:00
f = 1
触发了 python 回收机制
ljpCN
2021-03-27 12:24:41 +08:00
得看下 f.close 到底做了什么,直觉上感觉不调用会内存泄漏。另外,更想知道的是用 with 和手动调 close 哪个是更好的实践呢?前者少写了代码省心了但多了一层缩进。如果要在过程中打开多个文件就缩得更多。
geelaw
2021-03-27 12:25:17 +08:00
这样的写法在标准 Python 中可以导致文件在进程结束前不被关闭,因为在内存充足的时候,垃圾回收器可以选择完全不回收不可达对象。

在目前的 CPython 实现中,这种写法可以保证文件立刻被关闭,因为 CPython 采用引用计数来辅助管理内存,引用计数到达 0 的时候会立刻回收,从而关闭文件。

在 IronPython 中,则不一定,现在 CLR 提供要求暂时不运行 GC 的 API,如果在运行这段代码前,有人 commit 了足够的内存要求不运行 GC,且这段代码之后程序不再分配内存,则文件永远不会被关闭。

不要面向巧合编程。
GrayXu
2021-03-27 12:25:43 +08:00
取决于场景,如果不需要在某个时刻保证资源被释放,那隐式完成其实也可以吧。。
lqf96
2021-03-27 12:26:07 +08:00
@geelaw 都不需要 IronPython,PyPy 就已经火葬场了...
zictos
2021-03-27 12:31:41 +08:00
如果仅仅是用 open('test.txt', 'r', encoding='utf-8')打开文件,但没有做任何操作,发现 test.txt 文件是无法删除的。但只要做了别的操作或者一开始赋值给了变量后续又改变了变量的数据类型就可以删除了。
zictos
2021-03-27 12:35:00 +08:00
@ljpCN #5 问题在于文件能够删除了就肯定说明内存已经释放了
有时候我反倒不想看到 with 的缩进,因为我就是读取一下文件,本来也一两行代码就可以搞定。只是用 with 的确不容易忘记 close,效果应该是一样的。
Contextualist
2021-03-27 12:41:39 +08:00
如果只是一次性读 / 写,建议使用 pathlib:
from pathlib import Path
Path('test.txt').write_text('123', encoding='utf-8')
text = Path('test.txt').read_text(encoding='utf-8')

这些方法都是自带关闭文件的。
zhuangzhuang1988
2021-03-27 12:42:05 +08:00
接手的人 看了要流泪
webshe11
2021-03-27 12:42:14 +08:00
@lqf96 #8 试了一下,确实,macOS 下 lsof 发现 PyPy 7.3.3 不会自动关闭,CPython 3.9.2 2.7.17 都会自动关闭文件
个人觉得就写个 with 再缩进一下不算麻烦,如果实在嫌麻烦可以封装个 file_get_contents() 函数(滑稽)
zictos
2021-03-27 12:45:50 +08:00
@webshe11 #13 那看来还是跟解释器有关,兼容型不是很好。不过自己使用倒是没问题。
因为我的需求也重点是用在小脚本,比如有时候打算写一个本来就只有十几行的脚本,或者在安卓手机上用 termux 运行 python,这样比较方便。
kikikiabc
2021-03-27 12:46:51 +08:00
> 要不再封装成一个函数,传入文件名返回值,内部做好处理?

有,自带的 pathlib 已经封装好了的,确实是“传入文件名返回值”, 很好用
hxy100
2021-03-27 12:51:45 +08:00
@webshe11 PHP 乱入?
xiaolinjia
2021-03-27 12:58:03 +08:00
在流畅的 python 一书中有提到:
CPython 中的垃圾回收主要依靠引用计数,这容易实现,但是遇到引用循环容易泄露
内存,因此 CPython 2.0 ( 2000 年 10 月发布)实现了分代垃圾回收程序,它能把引用
循环中不可获取的对象销毁。
但是引用计数仍然作为一种基准存在,一旦引用数量归零,就立即销毁对象。这意味
着,在 CPython 中,这样写是安全的(至少目前如此):
open('test.txt', 'wt', encoding='utf-8').write('1, 2, 3')
这行代码是安全的,因为文件对象的引用数量会在 write 方法返回后归零,Python
在销毁内存中表示文件的对象之前,会立即关闭文件。然而,这行代码在 Jython 或
IronPython 中却不安全,因为它们使用的是宿主运行时( Java VM 和 .NET CLR )中的
垃圾回收程序,那些回收程序更复杂,但是不依靠引用计数,而且销毁对象和关闭文
件的时间可能更长。在任何情况下,包括 CPython,最好显式关闭文件;而关闭文件
的最可靠方式是使用 with 语句,它能保证文件一定会被关闭,即使打开文件时抛出
了异常也无妨。
AndyAO
2021-03-27 13:11:17 +08:00
单纯是为了方便的话可以用 With 来写个 Snippet
johnsona
2021-03-27 13:21:45 +08:00
@v2sir 好家伙 你这垃圾回收机制都学以致用了
imn1
2021-03-27 13:46:03 +08:00
“老子写的程序绝对没有 bug,也绝对不会耗时,锁文件又如何,爱咋咋地”

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/765647

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX