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

时间:2013-03-12 19:45:59

标签: python

我一直在编写一个很长的脚本,偶尔会构建大的dicts和/或列表,我想知道当我使用它们时用del删除它们是否可以改善性能。或者通常的做法是将这些物品留在周围以便通过垃圾收集来处理?这里的最佳做法是什么?感谢。

3 个答案:

答案 0 :(得分:7)

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

del唯一能做的就是从其范围中删除名称。 (或删除集合中的项目,或删除属性。但我认为这不是你在这里谈论的。)

实际上,这是:

del foo

等同于:

del LOCAL_SCOPE['foo']

所以这不会释放任何记忆:

massive_list = list(range(1000000))
same_massive_list = massive_list
del massive_list

...因为它所做的就是删除名称 massive_list。底层对象仍有另一个名称same_massive_list,因此它不会消失。 del不是用于控制Python内存管理的秘密钩子;它只是要求 Python 调用其内存管理的几种方法之一。

(顺便说一句,CPython被重新计算+循环收集,而不是垃圾收集。一旦最后一次引用就消失了,对象立即释放。垃圾不等待等待当然,其他实现做了不同的事情;例如,PyPy是垃圾收集。)

现在,如果您使用的名称是list / dict / whatever的 only 名称,则del肯定会导致其引用计数降至零,因此它将是释放。 但是,因为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()对词典做同样的事情。

我在名称上使用del的唯一地方是在类或模块范围内,我暂时需要一些辅助值,但真的不希望暴露它作为API的一部分。这真的很少见,但这是我遇到的唯一一个我真正想要“删除这个名字”语义的案例。

答案 1 :(得分:1)

del通常没有必要。

在CPython中,当没有对它们的引用时,对象就会消失。 del只删除对象的一个​​引用;如果还有其他对象的引用,它将保持不变,并且del实际上没有做任何改善你的记忆情况。

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

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

一个例外是循环引用,其中两个(或更多)对象相互引用但实际上没有一个可通过名称访问; Python定期垃圾收集这些,但是如果你在完成对象时打破了圆圈,你可以更快地释放它们。 (这可能只需要一个del!)但这种情况很有用的情况可能非常罕见。

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

答案 2 :(得分:0)

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

所以我的建议是不要打扰,除非你有理由这样做(例如python正在吃你所有的RAM)。