跳到正文
效率工具实用笔记关于本站
文件整理

给工具创建临时工作目录:TemporaryDirectory的生命周期

约 10 分钟阅读AI 辅助整理

用 with 语句创建临时目录,代码块结束时目录和内容自动删除;本文说明 name 属性、cleanup() 方法、ignore_cleanup_errors 参数、delete 参数和异常情况下的清理行为,全程只操作程序自建的临时目录。

本文要点

  1. TemporaryDirectory 对象有一个 name 属性,用来取这个临时目录的名字

  2. 有时候你不需要等到 with 结束才清理,比如工具分两段运行,中间那段的大文件已经用不上了,想早点释放

  3. 文档举了一个具体例子:在 Windows 上删除仍被打开的文件,可能抛出 PermissionError

给工具创建临时工作目录:TemporaryDirectory的生命周期的知识要点示意图
依据已审核正文摘取要点制作的示意图,非实物照片;请结合正文中的条件与范围阅读。要点摘自已审核正文;完整条件与说明见正文。查看高清图解 ↗
本文目录

先回答:临时目录在什么时候被删掉

如果你想让工具在运行期间有一个自己的目录放中间文件,运行完又不想手动去删,用 tempfile.TemporaryDirectory 最直接。

按 Python 官方 tempfile 文档的说明,TemporaryDirectory 会安全地创建一个临时目录,规则和 mkdtemp() 相同。这个对象可以作为上下文管理器使用。当上下文结束、或者这个临时目录对象被销毁时,新建的临时目录以及里面的全部内容都会从文件系统中被移除。

所以生命周期可以概括成一句话:进入 with 时创建,退出 with 时连同内容一起删除。你不需要自己写删除命令。文档把 TemporaryDirectory 列为提供自动清理的高层接口,而 mkstemp() 和 mkdtemp() 是需要手动清理的低层函数。

本文只讲程序自建的临时目录如何自动清理,不操作用户原有的任何目录。下面所有路径都是练习用的自建示例。

一个边界:清理不是绝对可靠的。文档专门警告,清理对“删除过程中目录树被修改”这种情况并不稳健;在 shutil.rmtree.avoids_symlink_attacks 为假的系统上,清理期间操作符号链接可能导致目录树之外的文件被删除。所以临时目录里不要放指向外部位置的符号链接。

用 with 拿到的 name 是什么,能拿来做什么

TemporaryDirectory 对象有一个 name 属性,用来取这个临时目录的名字。当它作为上下文管理器使用时,如果 with 语句里写了 as 子句,这个 name 会被赋给 as 后面的变量。

下面是一个自建示例,只创建临时目录并打印它的名字,不碰任何已有目录:

import tempfile

with tempfile.TemporaryDirectory() as tmpdirname:
    print("created temporary directory", tmpdirname)

运行这段代码,你会看到一行输出,形如 created temporary directory 后面跟一个系统临时目录下的随机路径。这个路径就是本次运行独有的工作目录。

拿到 name 之后,你可以在这个目录里放工具运行需要的中间文件。注意 name 是字符串形式的路径,你可以把它和 pathlib 的 Path 组合使用,例如把中间结果写到这个目录下的子路径。

关键点:不要把这个路径存下来留到 with 之外使用。退出 with 之后,这个目录已经被删除,路径虽然还在变量里,但指向的位置已经不存在了。

想在 with 内部提前清理,用 cleanup() 而不是自己删

有时候你不需要等到 with 结束才清理,比如工具分两段运行,中间那段的大文件已经用不上了,想早点释放。

文档说明,这个目录可以通过调用 cleanup() 方法显式清理。也就是说,在 with 内部调用一次 cleanup(),目录和内容就会被移除,不必等到退出上下文。

下面是一个自建示例,演示先写文件、再显式清理:

import tempfile
from pathlib import Path

tmp = tempfile.TemporaryDirectory()
work = Path(tmp.name)
(work / "step1.txt").write_text("示例中间结果", encoding="utf-8")
print("清理前存在:", (work / "step1.txt").exists())
tmp.cleanup()
print("清理后存在:", (work / "step1.txt").exists())

这段代码里,cleanup() 之后目录已经被移除,所以第二次 exists() 会返回 False。

注意:cleanup() 是显式清理,它和 with 退出时的隐式清理是同一套机制。不要用自己写的删除命令去代替它。

清理出错时会发生什么,ignore_cleanup_errors 管什么

清理不一定总是顺利。文档举了一个具体例子:在 Windows 上删除仍被打开的文件,可能抛出 PermissionError。

默认情况下,这类错误不会被吞掉。文档说明,如果 ignore_cleanup_errors 为假(默认),显式或隐式清理过程中出现的未处理异常会在清理发生的那个上下文中抛出——可能是你调用 cleanup() 的时候,可能是退出上下文管理器的时候,也可能是对象被垃圾回收或解释器关闭的时候。

如果把 ignore_cleanup_errors 设为真,这些异常会被忽略,剩余可删除的项目会以“尽力而为”的方式删除。

下面是一个自建示例,展示参数位置:

import tempfile

with tempfile.TemporaryDirectory(ignore_cleanup_errors=True) as tmpdirname:
    print("created temporary directory", tmpdirname)

这个参数适合什么场景:你的工具在退出时可能还有文件句柄没关,你又不想让清理失败把整个程序带崩。但它不是万能开关——文档说的是忽略未处理异常,并按尽力而为的方式删除剩余项,不保证一定删干净。

一个使用限制:本文只讨论程序自建临时目录的清理行为,不涉及清理用户原有目录,也不建议用这个参数去掩盖自己代码里没关文件的问题。

delete 参数:什么时候需要关掉自动清理

TemporaryDirectory 还有一个 delete 参数,用来在退出上下文时禁用对目录树的清理。

文档承认,让一个上下文管理器在退出时“不做事”看起来有点不寻常,但它在调试时有用,或者当你需要根据其他逻辑来决定是否清理时也有用。

也就是说,默认行为是退出即删;把 delete 设为假,退出时目录会保留下来。

下面是一个自建示例,只用于演示参数写法:

import tempfile

with tempfile.TemporaryDirectory(delete=False) as tmpdirname:
    print("created temporary directory", tmpdirname)

这段代码退出 with 之后,目录不会被自动删除。它的用途是排查问题:你想看看工具到底在临时目录里放了什么,就临时关掉清理。

需要提醒的是:关掉自动清理之后,这个目录就留在系统临时位置了,需要你自己后续处理。本文不教手写删除命令,也不建议把这个参数用在正式运行的工具里。

一个适用限制:delete 参数是较新版本才加入的。如果你的运行环境版本较旧,这个参数可能不存在,写进去会报错。本文不给出具体版本号,请以你所用环境的官方文档为准。

怎么检查清理是否真的发生了

自动清理是隐式发生的,容易让人不放心。你可以在自建示例里做一次前后对照,确认目录确实消失了。

下面这段代码只操作程序自建的临时目录:

import tempfile
from pathlib import Path

with tempfile.TemporaryDirectory() as tmpdirname:
    work = Path(tmpdirname)
    (work / "note.txt").write_text("示例内容", encoding="utf-8")
    print("with 内部,目录存在:", work.exists())
    print("with 内部,文件存在:", (work / "note.txt").exists())

print("with 外部,目录存在:", work.exists())

预期输出是:with 内部两行都是 True,with 外部一行是 False。如果最后一行是 True,说明清理没有按预期发生,可以从这几个方向排查:

1. 是否把 delete 设成了假。

2. 是否在 with 内部还有文件句柄没关,导致清理失败。

3. 是否设置了 ignore_cleanup_errors,把清理错误吞掉了。

以上排查顺序是编辑整理的检查方法,不是对某个具体环境的测试记录。

使用限制与参考资料

本文只讲 tempfile.TemporaryDirectory 的生命周期:创建、name 属性、cleanup()、ignore_cleanup_errors、delete 参数,以及如何检查清理结果。不涉及 mkstemp()、mkdtemp() 这类需要手动清理的低层函数,也不涉及临时文件的其他类型。

几条需要记住的限制:

- 清理不稳健:目录树在删除过程中被修改,或者清理期间操作符号链接,都可能出问题。临时目录里不要放指向外部的符号链接。

- 不要手写删除命令:这个类的设计目的就是自动清理。

- 不要跨 with 使用 name:退出上下文后路径已失效。

- 本文所有示例都是自建的练习代码,只创建程序自己的临时目录,不操作用户原有目录,也不执行系统修改。

参考资料:Python 官方 tempfile 模块文档,https://docs.python.org/3/library/tempfile.html

观看知识要点视频 18 秒

18秒无旁白要点导览,文字来自已审核正文;完整步骤、条件及参考资料见下方。

参考资料

以下原始资料提供本文依据;请结合日期、适用条件和产品说明查阅。

请结合原始资料的适用条件阅读。

返回文件整理 →