假设我在 python 中有一个相当大的列表my_list
,我想截断它。我可以通过删除它或将新列表分配给my_list
. 更好的方法是什么?
my_list = range(1, 10000)
方法一:
my_list = list()
print len(my_list) # prints 0
方法二:
del my_list[:]
print len(my_list) # prints 0
我觉得方法 2 是更合适的方法,对吗?
在内部,Python 使用一种称为引用计数的机制来跟踪数据是否仍然可以访问。每次新的“变量”引用数据时,数据的引用计数器就会增加。每次“变量”停止引用数据时,数据的引用计数器就会递减。当引用计数器达到 0 时,数据被删除(它的“释放函数”被调用):http ://docs.python.org/2/c-api/refcounting.html
例如,这会创建一个“大”列表,该列表几乎一创建就被删除,因为没有变量可以“增加”其引用计数器:
range(1, 10000)
这将创建一个新列表,允许您通过引用它并将列表my_list
的引用计数器设置为“1”
my_list = range(1, 10000)
编写以下语句,现在将减少列表的引用计数器。假设您没有其他对它的引用,则该计数器达到 0,因此该列表被删除。
my_list = None
最后一个例子:
my_list = range(1, 10000)
del my_list[:]
这个创建了一个包含 10000 个项目的列表。参考计数器为“1”。第二条语句删除列表的 10000 项——但您仍然有一个对空列表的引用。你看出区别了吗?
顺便说一句,引用计数是一种很好的自动释放机制,它具有确定性的好处(与 Java 垃圾收集器相反)。但是,有一种情况下引用计数不起作用:如果你有循环依赖。对象 A 引用引用对象 A 的对象 B。在这种情况下,只要“圆”没有被破坏,A 或 B 引用计数器都不会达到 0。但这超出了你的问题,我想。无论如何,对于那些包含非主控循环依赖的程序,Python 有一个可选的垃圾收集器来释放这些循环。默认情况下,垃圾收集器已启用。很容易检查:
>>> import gc
>>> gc.isenabled()
True
最后一点,即使垃圾收集器也受到限制,因为它不会使用终结器 ( __del__
) 释放包含对象的循环。有关该http://arctrix.com/nas/python/gc/的合理信息,请参阅以下链接
删除是我更喜欢的,因为这两个操作几乎都需要相同的时间。并del
清除与列表关联的任何内存引用并将其分配给新列表可能会导致旧内存无法正确清除。