【问题标题】:Does deleting a dictionary close the file descriptors inside the dict?删除字典会关闭字典中的文件描述符吗?
【发布时间】:2021-12-30 02:52:54
【问题描述】:

澄清

确实有两个问题。更新以使这一点更清晰。

我有:

t = {
    'fd': open("filename", 'r')
}

我了解del t['fd'] 删除了密钥并关闭了文件。对吗?

del t 是否对包含的对象(在这种情况下为 fd)调用 del

【问题讨论】:

  • 它最终会,但可能要等到脚本结束——所以指望它不是一个好主意。
  • 一般情况下,最好明确关闭文件(使用closewith 语句)。删除变量(直接或作为字典的一部分)并不是真正的正确方法
  • 根据文档:“警告在不使用 with 关键字或调用 f.close() 的情况下调用 f.write() 可能会导致 f.write() 的参数未完全写入磁盘,即使程序成功退出。” docs.python.org/3/tutorial/…

标签: python io garbage-collection file-descriptor


【解决方案1】:

您想要做的事情的行为是不确定的。根据 Python(CPython、PyPi、...)的实现和内部功能,这可能有效或无效:

工作示例

t = {
    'fd': open('data.txt', 'r')
}

def hook_close_fd():
    print('del dictionary, close the file')

t['fd'].close = hook_close_fd

del t

输出:

del dictionary, close the file

在这种情况下,close 函数在删除时被调用

无效示例

t = {
    'fd': open('data.txt', 'r')
}

def hook_close_fd():
    print('del dictionary, close the file')

t['fd'].close = hook_close_fd

3 / 0

第一次运行的输出:

---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-211-2d81419599a9> in <module>
     10 t['fd'].close = hook_close_fd
     11 
---> 12 3 / 0

ZeroDivisionError: division by zero

第二次运行的输出:

del dictionary, close the file
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-212-2d81419599a9> in <module>
     10 t['fd'].close = hook_close_fd
     11 
---> 12 3 / 0

ZeroDivisionError: division by zero

如您所见,当引发异常时,您无法确定文件描述符是否会正确关闭(尤其是如果您自己没有捕获异常)。

【讨论】:

  • 好吧,我觉得你的答案和我的相得益彰,不知道删除描述符的时候直接调用了close。
  • @martineau,这只是通过在删除后添加睡眠来测试。然而,这仍然证明不了。这显然不是保证,而是由实现定义的。
  • 在某些情况下,最后一次引用的持续时间比您预期的要长;例如,如果引发异常,它将保留对所有局部变量的引用
  • 无论如何,它被证明是不安全的;如果它恰好在某些情况下起作用,那是一个实现细节,甚至只是运气
  • @JiříBaum。我测试了一个异常,两次运行之间的行为不同。好点。
【解决方案2】:

你问题的两个部分有完全不同的答案。

  • 删除一个变量来关闭文件是不可靠的;有时它起作用,有时它不起作用,或者它起作用但以一种令人惊讶的方式。有时它可能会丢失数据。它肯定不会以有用的方式报告文件错误。

    关闭文件的正确方法是 (a) 使用 with 语句,或 (b) 使用 .close() 方法。

  • 删除一个对象确实会删除所有包含的对象,但有几点需要注意:

    • 如果(某些)这些对象也在另一个变量中,它们将继续存在,直到另一个变量也被删除;

    • 如果这些对象相互引用,它们可能会在之后继续存在一段时间并在以后被删除;和

    • 对于不可变对象(字符串、整数),Python 可能会决定保留它们作为优化,但这对我们来说大多是不可见的,并且在任何情况下都会因版本而异。

【讨论】:

  • 注意:当您使用.close() 而不是上下文管理器(即with)时,您应该使用try-finally 来确保文件实际上已关闭,即使发生了一些异常。
  • 从所有答案中我得到del t['fd'] 不会确定性地立即关闭文件,即使这是对文件对象的最后引用。然而,这个结论总是被暗示,从来没有明确说明过参考,只是建议。这对我来说听起来很奇怪。我想一个文件对象有一个析构函数,这个析构函数关闭了文件。真的吗?如果为真,在最后一次引用文件对象时调用del 不应立即可靠地关闭文件? (我应该把它变成一个不同的问题吗?)
  • python 手册中是这么说的; “可能”丢失数据。见docs.python.org/3/tutorial/…的红框
  • 在某些情况下,她的罚款可能根本无法正常关闭;特别是如果句柄最终出现在全局变量或引用循环中。另一件事是,如果文件关闭有错误,没有办法报告它;无处可引发异常。
  • 无关紧要的主要情况是文件是否以只读方式打开并且脚本是短暂的;在这种情况下,它是否关闭都没有关系。不过,正确地做这件事仍然是一个好习惯。
【解决方案3】:

没有。您必须关闭您打开的文件(见注释)。

或者,但它可能不适合您的项目,以更安全的方式在上下文管理器中打开它。

with open("filename", 'r') as fd:
    ...

如果您同时打开未知数量的文件,您可能需要编写自己的上下文管理器或更简单地使用contextlib.ExitStack

注意: 从 : "3.10.0 文档/ Python 教程 / 7.输入输出/ 7.2.读取和写入文件 https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files": 警告调用 f.write() 而不使用 with 关键字或调用 f.close() 可能会导致 f.write() 的参数没有完全写入磁盘,即使程序成功退出.

【讨论】:

    【解决方案4】:

    您的问题没有您想象的那么简单。但归根结底,这一切都归结为了解指针是什么以及垃圾收集器的工作原理。

    确实,通过执行t['fd'],您可以删除字典中的那个条目。您所做的是删除指向该条目的指针。如果你有一本字典如下:

    t = { 'a':3, 'b':4 }
    

    然后当您执行del t 时,您会删除指向字典t 的指针。由于没有进一步引用字典键,垃圾收集器也会删除它们,从而释放所有字典内存。

    然而,只要你有一个文件描述符,你就可以删除它,但这样做是不可取的,因为文件描述符(fd,指向文件的指针等等)是程序员与之交互的方式一个文件,如果突然删除描述符,文件的状态可能会因为处于不一致的状态而损坏。

    因此,最好在停止处理文件之前调用close 函数。此功能会为您处理所有这些事情。

    【讨论】:

      【解决方案5】:

      是的,删除变量 t 会关闭文件 (using psutil to show open files per process):

      import psutil
      
      
      def find_open_files():
          for proc in psutil.process_iter():
              if proc.name() == 'python3.9':
                  print(proc.open_files())
      
      
      filename = '/tmp/test.txt'
      t = {'fd': open(filename, 'r')}
      find_open_files()
      del t
      find_open_files()
      

      输出:

      [popenfile(path='/private/tmp/test.txt', fd=3)]
      []
      

      【讨论】:

      • 正如在其他各种答案和 cmets 中所讨论的,这是不可靠的,在某些情况下可能会丢失数据
      • 我回答的时候,问题是关于:Does deleting an object delete all contained objects?不是,如果有副作用的话。
      • 如果是这个问题,那么“是的,删除变量 t 会关闭文件”是一个奇怪的答案,你不觉得吗? (因为问题不是关于关闭文件。)虽然当问题基于不正确的前提并且包含多个问题时,这是一个常见问题......
      猜你喜欢
      • 1970-01-01
      • 2022-01-20
      • 1970-01-01
      • 1970-01-01
      • 2017-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-26
      相关资源
      最近更新 更多