在Python良好实践中定期删除长目录/列表?

在Python良好实践中定期删除长目录/列表?,python,Python,我一直在编写一个长脚本,偶尔会构建大型dict和/或列表,我想知道在我使用完它们后,是否可以通过使用del删除它们来提高性能。或者让垃圾收集来处理这些东西是正常的做法吗?这里的最佳实践是什么?谢谢。del通常是不必要的 在CPython中,对象在没有引用时会消失del仅删除对对象的一个引用;如果还有其他对该对象的引用,它将保留,并且del对改善您的记忆状况没有任何作用 相反,简单地将变量重新分配给不同的对象(例如,在循环的顶部创建一个新的空列表)也会减少对该对象的引用,隐式地执行与del相同的操

我一直在编写一个长脚本,偶尔会构建大型dict和/或列表,我想知道在我使用完它们后,是否可以通过使用
del
删除它们来提高性能。或者让垃圾收集来处理这些东西是正常的做法吗?这里的最佳实践是什么?谢谢。

del
通常是不必要的

在CPython中,对象在没有引用时会消失
del
仅删除对对象的一个引用;如果还有其他对该对象的引用,它将保留,并且
del
对改善您的记忆状况没有任何作用

相反,简单地将变量重新分配给不同的对象(例如,在循环的顶部创建一个新的空列表)也会减少对该对象的引用,隐式地执行与
del
相同的操作。如果此时没有对该对象的其他引用,将立即释放该对象

还要记住,当函数返回时,局部变量会消失,因此不需要显式地
del
函数中定义的任何名称

循环引用是一个例外,其中两个(或多个)对象相互引用,但实际上无法通过名称访问任何对象;Python会定期对这些对象进行垃圾收集,但如果在处理完对象后打破循环,则可以更快地释放它们。(这可能只需要一个
del
!)不过,在这种情况下很可能很少见


在IronPython(在.NET CLR上运行)或Jython(在JVM上运行)中,最佳内存管理策略可能不同,因为使用的是底层VM的垃圾收集器。

del
并不等同于free(3)。它不会强制Python释放内存。它可能根本不会释放内存。您应该避免将其与内存使用完全关联

del
所做的唯一一件事就是从其作用域中删除一个名称。(或者从集合中删除一个项目,或者删除一个属性。但我想这不是您在这里讨论的内容。)

实际上,这:

del foo
相当于:

del LOCAL_SCOPE['foo']
所以这不会释放任何内存:

massive_list = list(range(1000000))
same_massive_list = massive_list
del massive_list
…因为它所做的只是删除名称
massible\u list
。底层对象仍然有另一个名称,
same\u massible\u list
,因此它不会消失
del
不是控制Python内存管理的秘密钩子;这只是要求Python调用其内存管理的几种方法之一

(顺便说一句,CPython是refcounted+cycle收集的,而不是垃圾收集的。对象的最后一次引用消失后会立即释放。垃圾不会四处等待清理。当然,其他实现会做不同的事情;例如,PyPy是垃圾收集的。)

现在,如果您使用的名称是list/dict/which的唯一名称,那么
del
肯定会导致其refcount降为零,因此它将被释放但是,因为
del
的语义实际上是关于删除名称的,所以我不会在这种情况下使用它。我会让变量退出作用域(如果可行),或者将名称重新分配到一个空白列表,或者
None
,或者任何对您的程序有意义的东西。您甚至可以就地清空该列表,即使同一列表中有多个名称,该操作也会起作用:

foo = list(range(1000000))
bar = foo
foo[:] = []
# Both `bar` and `foo` still refer to the original list, but now it's empty
您可以使用
d.clear()
对dict执行相同的操作


我对名称使用
del
的唯一地方是在类或模块作用域中,在那里我暂时需要一些helper值,但真的不想将其作为API的一部分公开。这是非常罕见的,但这是我遇到的唯一一个真正需要“删除此名称”语义的情况。

Python的优点之一(与C等语言相比)是,一般来说,您不必担心内存管理的细节,您可以专注于程序的用途


所以我的建议是,除非你有理由这么做,否则不要麻烦(例如,python正在吃掉你所有的RAM)

如果我没记错的话,从列表/dict中删除值只会将值释放到GC,并停止在列表dict中引用它们,因此实际上您仍然有所有的内存要由GC处理,它只是被分解成小块。但我可能错了,我还并没有在CPython中对python进行过广泛的研究,若它们超出范围,就会被收集(除了循环引用)。你的问题也不清楚你是指删除列表成员还是整个列表…就像这个答案,特别是关于清空容器的部分。我觉得
del foo[:]
更简洁。我喜欢保留
del
仅用于删除名称。列表和dict都有
.pop
,列表有切片语法,所以不需要特殊的构造;删除变量只能(ish)使用
del
。这也避免了扫描问题:当您看到
del super\u duper\u long\u name[2]
时,直到您读到这一行的末尾,您才真正知道它是哪种味道的
del