关闭ipython中所有打开的文件

15 投票
2 回答
42069 浏览
提问于 2025-04-17 10:59

有时候在使用ipython的时候,你可能会遇到一个问题,这个问题发生在一个打开了文件进行写入的函数里。这意味着下次你再运行这个函数时,会出现一个值错误,

值错误:文件 'filename' 已经打开。请在重新以写入模式打开之前先关闭它。

但是,由于这个函数出错了,文件的句柄(也就是在函数内部创建的那个)就丢失了,所以无法关闭。解决这个问题的唯一办法似乎就是关闭ipython会话,这时你会看到这样的提示:

正在关闭剩余的打开文件:filename... 完成

有没有办法让ipython在不退出会话的情况下关闭这些文件呢?

2 个回答

7

这里有几个建议:

  • 在处理文件时,最好总是使用 finally(或者 with 语句),这样可以确保文件被正确关闭。
  • 你可以直接关闭一些非标准的文件描述符,方法是使用 os.close(n),其中 n 是大于2的数字(这适用于Unix系统,所以你可以查看 /proc/ipython_pid/fd/ 来看看当前进程打开了哪些描述符)。
  • 你可以检查捕获的堆栈帧中的局部变量,看看能否找到那个出问题的文件的引用并将其关闭……可以查看 sys.last_traceback
14

在处理文件时,建议你总是使用 with 语句。比如,你可以这样写:

with open("x.txt") as fh:
    ...do something with the file handle fh

这样做的好处是,如果在 with 代码块执行过程中出现了问题,比如发生了错误,文件会被自动关闭。想了解更多,可以查看关于 with 的文档

补充说明:根据评论中的讨论,提问者似乎需要同时打开多个文件,并且需要同时使用多个文件中的数据。显然,给每个打开的文件都写一个嵌套的 with 语句并不是个好主意,这样会让代码变得复杂,而我们通常希望代码保持简单。

一个可行的办法是把计算过程放在一个 try/finally 代码块中。比如:

file_handles = []
try:
    for file in file_list:
        file_handles.append(open(file))

    # Do some calculations with open files

finally:
    for fh in file_handles:
        fh.close()

finally 代码块中包含的代码会在任何 tryexceptelse 代码块执行完后运行,即使发生了错误也会执行。从文档中可以了解到:

如果有 finally,它会指定一个“清理”处理程序。try 代码块会被执行,包括任何 exceptelse 代码块。如果在这些代码块中发生了错误且没有被处理,这个错误会被暂时保存。接着会执行 finally 代码块。如果有保存的错误,它会在 finally 代码块结束时被重新抛出。如果 finally 代码块抛出了另一个错误,或者执行了返回或跳出语句,那么之前保存的错误就会丢失。在执行 finally 代码块时,程序无法访问错误信息。

撰写回答