0

0

分析用Python脚本关闭文件操作的机制

php中文网

php中文网

发布时间:2016-06-06 11:19:25

|

1240人浏览过

|

来源于php中文网

原创

如果不用“with”,那么python会在何时关闭文件呢?答案是:视情况而定。

Python程序员最初学到的东西里有一点就是可以通过迭代法很容易地遍历一个打开文件的全文:

f = open('/etc/passwd')
for line in f:
  print(line)

注意上面的代码具有可行性,因为我们的文件对象“f”是一个迭代器。换句话说,“f“ 知道在一个循环或者任何其他的迭代上下文中做什么,比如像列表解析。

我的Python课堂上的大多数学生都具有其他编程语言背景,在使用以前所熟悉的语言时,他们总是在完成文件操作时被期望关闭文件。因此,在我向他们介绍了Python文件操作的内容不久后他们问起如何在Python中关闭文件时,我一点都不惊讶。

最简单的回答就是我们可以通过调用f.close()显式地关闭文件。一旦我们关闭了文件,该文件对象依然存在,但是我们无法再通过它来读取文件内容了,而且文件对象返回的可打印内容也表明文件已经被关闭。

>>> f = open('/etc/passwd')
>>> f

>>> f.read(5)
'##n# '
 
f.close()
>>> f

 
f.read(5)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
 in ()
----> 1 f.read(5)
ValueError: I/O operation on closed file

所以是这样,我在用Python编程的时候,很少明确地对文件调用 “close” 方法。此外,你也很可能不想或不必那样做。

打开文件的优选最佳实践方式是使用 “with” 语句,就像如下所示:

with open('/etc/passwd') as f:
  for line in f:
    print(line)

“with”语句对 “f” 文件对象调用在Python中称作“上下文管理器”的方法。也就是说,它指定 “f” 为指向 /etc/passwd 内容的新的文件实例。在 “with” 打开的代码块内,文件是打开的,而且可以自由读取。

立即学习Python免费学习笔记(深入)”;

然而,一旦Python代码从 “with” 负责的代码段退出,文件会自动关闭。试图在我们退出 “with”代码块后从 f 中读取内容会导致和上文一样的 ValueError 异常。所以,通过使用 “with”,你避免了显式地关闭文件的操作。Python 会以一种不那么有 Python 风格的方式在幕后神奇而静静地替你关闭文件。

但是你不显式地关闭文件会怎样?如果你有点懒,既不使用 “with” 代码块也不调用f.close()怎么办?这时文件会什么时候关闭?何时应该关闭文件?

我之所以问这个,是因为我教了这么多年Python,确信努力教授“with”或上下文管理器的同时又教很多其它的话题超出了学生接受的范围。在介绍性课程谈及 “with” 时,我一般会告诉学生在他们职业生涯中遇到这个问题时,让Python去关闭文件就好,不论文件对象的应用计数降为0还是Python退出时。

在我的Python文件操作免费e-mail课程中,我并没有在所有的解决方案中使用with,想看看如何。结果一些人质疑我,说不使用“with”会向人们展示一种糟糕的实践方案并且会有数据未写入磁盘的风险。

我收到了很多关于此话题的邮件,于是我问自己:如果我们没有显式地关闭文件或者没用“with”代码块,那么Python会何时关闭文件?也就是说,如果我让文件自动关闭,那么会发生什么?

我总是假定当对象的引用计数降为0时,Python会关闭文件,进而垃圾回收机制清理文件对象。当我们读文件时很难证明或核实这一点,但写入文件时却很容易。这是因为当写入文件时,内容并不会立即刷新到磁盘(除非你向“open”方法的第三个可选参数传入“False”),只有当文件关闭时才会刷新。

于是我决定做些实验以便更好地理解Python到底能自动地为我做什么。我的实验包括打开一个文件、写入数据、删除引用和退出Python。我很好奇数据是什么时候会被写入,如果有的话。

好买卖商城
好买卖商城

好买卖商城开源商城 是基于Opencart网店系统,针对中文用户而改进的本地化分支,是真正的开源PHP中文网店系统,兼容Opencart的插件。该系统具有易于操作的可视化安装界面、完善的前台商品展示和户在线购物车功能、强大的后台管理和维护功能模块简单易用,灵活的插件机制,更易于扩展。另外,好买卖商城开源商城 还集成集成了支付宝等支付和物流插件,更适合中文用户使用。 好买卖商城2.0开源商城流程进行

下载

我的实验是这个样子:

f = open('/tmp/output', 'w')
f.write('abcn')
f.write('defn')
# check contents of /tmp/output (1)
del(f)
# check contents of /tmp/output (2)
# exit from Python
# check contents of /tmp/output (3)

我在Mac平台上用Python 2.7.9 做了第一个实验,报告显示在阶段一文件存在但是是空的,阶段二和阶段三中文件包含所有的内容。这样,在CPython 2.7中我最初的直觉似乎是正确的:当一个文件对象被垃圾回收时,它的 __del__ (或者等价的)方法会刷新并关闭文件。而且在我的IPython进程中调用“lsof”命令显示文件确实在引用对象移除后被关闭了。

那 Python3 如何呢?我在Mac上 Python 3.4.2 环境下做了以上的实验,得到了相同的结果。移除对文件对象最后的引用后会导致文件被刷新并且被关闭。

这对于 Python 2.7 和 3.4 很好。但是在 PyPy 和 Jython下的替代实现会怎样呢?或许情况会有些不同。

于是我在 PyPy 2.7.8 下做了相同的实验。而这次,我得到了不同的结果!删除文件对象的引用后——也就是在阶段2,并没有导致文件内容被刷入磁盘。我不得不假设这和垃圾回收机制的不同或其他在 PyPy 和 CPython中工作机制的不同有关系。但是如果你在 PyPy中运行程序,就绝不要指望仅仅因为文件对象的引用结束,文件就会被刷新和关闭。命令 lsof 显示直到Python进程退出时文件才会被释放。

为了好玩,我决定尝试一下 Jython 2.7b3. 结果Jython 表现出了和PyPy一样的行为。也就是说,从 Python 退出确实会确保缓存中的数据写入磁盘。

我重做了这些实验,但是我把 “abcn”和 “defn”换成了 “abcn”*1000 和“defn”*1000.

在 Python 2.7 的环境下,“abcn” * 1000 语句执行后没有任何东西写入。但“defn” * 1000 语句执行后,文件包含有4096个字节——可能代表缓冲区的大小。调用 del(f) 删除文件对象的引用导致数据被刷入磁盘和文件关闭,此时文件中共有8000字节的数据。所以忽略字符串大小的话 Python 2.7 的行为表现基本相同。唯一不同的是如果超出了缓冲区的大小,那么一些数据将在最后文件关闭数据刷新前写入磁盘。

换做是Python 3的话,情况就有些不同了。f.write执行后没有任何数据会写入。但是文件对象引用一旦结束,文件就会刷新并关闭。这可能是缓冲区很大的缘故。但毫无疑问,删除文件对象引用会使文件刷新并关闭。

至于 PyPy 和 Jython,对大文件和小文件的操作结果都一样:文件在 PyPy 或 Jython 进程结束的时候刷新并关闭,而不是在文件对象的引用结束的时候。

为了再次确认,我又使用 “with” 进行了实验。在所有情况下,我们都能够轻松的预测文件是何时被刷新和关闭的——就是当退出代码段,并且上下文管理器在后台调用合适方法的时候。

换句话说,如果你不使用“with”,那么至少在非常简单的情形下,你的数据不一定有丢失的危险。然而你还是不能确定数据到底是在文件对象引用结束还是程序退出的时候被保存的。如果你假定因为对文件唯一的引用是一个本地变量所以文件在函数返回时会关闭,那么事实一定会让你感到吃惊。如果你有多个进程或线程同时对一个文件进行写操作,那么你真的要非常小心了。

或许这个行为可以更好地定义不就可以在不同的平台上表现得基本一致了吗?也许我们甚至可以看看Python规范的开始,而不是指着CPython说“Yeah,不管版本如何总是对的”。

我依然觉得“with”和上下文管理器很棒。而且我想对于Python新手,理解“with”的工作原理很难。但我还是不得不提醒新手开发者注意:如果他们决定使用Python的其他可选版本,那么会出现很多不同于CPython的古怪情况而且如果他们不够小心,甚至会深受其害。

相关文章

python速学教程(入门到精通)
python速学教程(入门到精通)

python怎么学习?python怎么入门?python在哪学?python怎么学才快?不用担心,这里为大家提供了python速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

65

2025.12.31

php网站源码教程大全
php网站源码教程大全

本专题整合了php网站源码相关教程,阅读专题下面的文章了解更多详细内容。

43

2025.12.31

视频文件格式
视频文件格式

本专题整合了视频文件格式相关内容,阅读专题下面的文章了解更多详细内容。

35

2025.12.31

不受国内限制的浏览器大全
不受国内限制的浏览器大全

想找真正自由、无限制的上网体验?本合集精选2025年最开放、隐私强、访问无阻的浏览器App,涵盖Tor、Brave、Via、X浏览器、Mullvad等高自由度工具。支持自定义搜索引擎、广告拦截、隐身模式及全球网站无障碍访问,部分更具备防追踪、去谷歌化、双内核切换等高级功能。无论日常浏览、隐私保护还是突破地域限制,总有一款适合你!

41

2025.12.31

出现404解决方法大全
出现404解决方法大全

本专题整合了404错误解决方法大全,阅读专题下面的文章了解更多详细内容。

204

2025.12.31

html5怎么播放视频
html5怎么播放视频

想让网页流畅播放视频?本合集详解HTML5视频播放核心方法!涵盖<video>标签基础用法、多格式兼容(MP4/WebM/OGV)、自定义播放控件、响应式适配及常见浏览器兼容问题解决方案。无需插件,纯前端实现高清视频嵌入,助你快速打造现代化网页视频体验。

9

2025.12.31

关闭win10系统自动更新教程大全
关闭win10系统自动更新教程大全

本专题整合了关闭win10系统自动更新教程大全,阅读专题下面的文章了解更多详细内容。

8

2025.12.31

阻止电脑自动安装软件教程
阻止电脑自动安装软件教程

本专题整合了阻止电脑自动安装软件教程,阅读专题下面的文章了解更多详细教程。

3

2025.12.31

html5怎么使用
html5怎么使用

想快速上手HTML5开发?本合集为你整理最实用的HTML5使用指南!涵盖HTML5基础语法、主流框架(如Bootstrap、Vue、React)集成方法,以及无需安装、直接在线编辑运行的平台推荐(如CodePen、JSFiddle)。无论你是新手还是进阶开发者,都能轻松掌握HTML5网页制作、响应式布局与交互功能开发,零配置开启高效前端编程之旅!

2

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

相关下载

更多

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 0.6万人学习

Django 教程
Django 教程

共28课时 | 2.6万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.0万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号