我有类似的东西:
a = [instance1, instance2, ...]
如果我做了
del a[1]
instance2从列表中删除,但是实例2的析构函数方法是否被调用?
我对此感兴趣,因为我的代码使用了大量内存,我需要释放内存从列表中删除实例.
来自像c ++这样的语言(正如我所做的那样),这往往是许多人在第一次学习Python时难以掌握的主题.
底线是这样的:当你这样做时del XXX
,你永远不会*在你使用时删除一个对象del
.您只是删除对象引用.但是,在实践中,假设没有其他参考instance2
对象放置,从列表中删除它将根据需要释放内存.
如果您不理解对象和对象引用之间的区别,请继续阅读.
Python:按值传递,或通过引用传递?您可能熟悉通过引用或值将参数传递给函数的概念.但是,Python以不同的方式做事.参数始终通过对象引用传递.阅读本文以获得有用的解释.
总结一下:这意味着当你将一个变量传递给一个函数时,你没有传递变量值的副本(按值传递),也没有传递对象本身 - 即内存中值的地址.您正在传递间接引用内存中保存的值的名称对象.
这与del
... 有什么关系?
好吧,我会告诉你的.
说你这样做:
def deleteit(thing): del thing mylist = [1,2,3] deleteit(mylist)
......你认为会发生什么?已经mylist
被从全局名字空间中删除?
答案是不:
assert mylist # No error
原因是当您del thing
在deleteit
函数中执行时,您只是删除对该对象的本地对象引用.该对象引用仅存在于函数内部.作为侧边栏,您可能会问:是否可以在函数内部从全局命名空间中删除对象引用?答案是肯定的,但您必须首先将对象引用声明为全局命名空间的一部分:
def deletemylist(): global mylist del mylist mylist = [1,2,3] deletemylist() assert mylist #ERROR, as expected把它们放在一起
现在回到原来的问题.在任何名称空间中,当您执行此操作时:
del XXX
...您没有删除XXX表示的对象.你不能这样做.您只删除了对象引用 XXX
,它引用了内存中的某个对象.对象本身由Python内存管理器管理.这是一个非常重要的区别.
请注意,因此,当您覆盖__del__
某个对象的方法时,该对象在删除对象时被调用(而不是对象引用!):
class MyClass(): def __del__(self): print(self, "deleted") super().__del__() m = MyClass() del m
... __del__
方法中的print语句不一定会在您执行后立即发生del m
.它只发生在删除对象本身的时间点,这不取决于你.这取决于Python内存管理器.删除所有名称空间中的所有对象引用后,__del__
最终将执行该方法.但不一定立即.
删除作为列表一部分的对象引用时也是如此,就像在原始示例中一样.当你这样做时del a[1]
,只a[1]
删除对所指示的对象的对象引用,并且__del__
可以立即调用或不调用该对象的方法(尽管如前所述,一旦没有对该对象的引用,它将最终被调用,并且该对象由内存管理器进行垃圾回收).
因此,不建议您将__del__
方法放在想要立即执行的方法中del mything
,因为它可能不会发生这种情况.
*我相信它永远不会.不可避免地有人可能会回复我的回答,并发表评论,讨论该规则的例外情况.但是whatevs.