删除字典会关闭字典中的文件描述符吗?
Does deleting a dictionary close the file descriptors inside the dict?
澄清
确实有两个问题。已更新以使其更清楚。
我有:
t = {
'fd': open("filename", 'r')
}
我了解 del t['fd']
删除密钥并关闭文件。对吗?
是否 del t
对包含的对象调用 del
(在本例中为 fd
)?
没有。您必须关闭打开的文件(见注释)。
或者,但它可能不适合您的项目,以更安全的方式在上下文管理器中打开它。
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() 的参数未被完全写入到磁盘,即使程序成功退出。
你的问题没有你想象的那么微不足道。但归根结底,这一切都归结为理解什么是指针以及垃圾收集器的工作原理。
确实,通过 t['fd']
,您可以删除字典中的该条目。您所做的是删除指向该条目的指针。如果你有如下字典:
t = { 'a':3, 'b':4 }
然后当您执行 del t
时,您删除了指向字典 t
的指针。由于因此没有进一步引用字典键,垃圾收集器也会删除它们,从而释放所有字典内存。
但是,只要您有文件描述符,就可以将其删除,但这样做并不可取,因为文件描述符(fd
、指向文件的指针等)是一种方式程序员与文件交互,如果描述符被突然删除,文件的状态可能会因处于不一致状态而被破坏。
因此,最好在停止处理文件之前调用 close
函数。此功能会为您处理所有这些事情。
您想做的事情的行为是不确定的。根据 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
如您所见,当引发异常时,您无法确定文件描述符是否会正确关闭(尤其是如果您自己没有捕获异常)。
是,删除变量 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)]
[]
你的问题的两个部分有完全不同的答案。
删除变量关闭文件不靠谱;有时有效,有时无效,或者有效但以令人惊讶的方式。有时它可能会丢失数据。它肯定无法以有用的方式报告文件错误。
关闭文件的正确方法是 (a) 使用 with
语句,或 (b) 使用 .close()
方法。
删除对象确实会删除所有包含的对象,但有几点需要注意:
如果这些对象(中的一些)也在另一个变量中,它们将继续存在,直到另一个变量也被删除;
如果这些对象相互引用,它们可能会在之后继续存在一段时间,然后被删除;和
对于不可变对象(字符串、整数),Python 可能会决定保留它们作为优化,但这大部分对我们来说是不可见的,并且在任何情况下都会有所不同版本之间。
澄清
确实有两个问题。已更新以使其更清楚。
我有:
t = {
'fd': open("filename", 'r')
}
我了解 del t['fd']
删除密钥并关闭文件。对吗?
是否 del t
对包含的对象调用 del
(在本例中为 fd
)?
没有。您必须关闭打开的文件(见注释)。
或者,但它可能不适合您的项目,以更安全的方式在上下文管理器中打开它。
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() 的参数未被完全写入到磁盘,即使程序成功退出。
你的问题没有你想象的那么微不足道。但归根结底,这一切都归结为理解什么是指针以及垃圾收集器的工作原理。
确实,通过 t['fd']
,您可以删除字典中的该条目。您所做的是删除指向该条目的指针。如果你有如下字典:
t = { 'a':3, 'b':4 }
然后当您执行 del t
时,您删除了指向字典 t
的指针。由于因此没有进一步引用字典键,垃圾收集器也会删除它们,从而释放所有字典内存。
但是,只要您有文件描述符,就可以将其删除,但这样做并不可取,因为文件描述符(fd
、指向文件的指针等)是一种方式程序员与文件交互,如果描述符被突然删除,文件的状态可能会因处于不一致状态而被破坏。
因此,最好在停止处理文件之前调用 close
函数。此功能会为您处理所有这些事情。
您想做的事情的行为是不确定的。根据 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
如您所见,当引发异常时,您无法确定文件描述符是否会正确关闭(尤其是如果您自己没有捕获异常)。
是,删除变量 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)]
[]
你的问题的两个部分有完全不同的答案。
删除变量关闭文件不靠谱;有时有效,有时无效,或者有效但以令人惊讶的方式。有时它可能会丢失数据。它肯定无法以有用的方式报告文件错误。
关闭文件的正确方法是 (a) 使用
with
语句,或 (b) 使用.close()
方法。删除对象确实会删除所有包含的对象,但有几点需要注意:
如果这些对象(中的一些)也在另一个变量中,它们将继续存在,直到另一个变量也被删除;
如果这些对象相互引用,它们可能会在之后继续存在一段时间,然后被删除;和
对于不可变对象(字符串、整数),Python 可能会决定保留它们作为优化,但这大部分对我们来说是不可见的,并且在任何情况下都会有所不同版本之间。