从列表中调用元素的析构函数 [英] Call destructor of an element from a list

查看:81
本文介绍了从列表中调用元素的析构函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有类似的东西:

a = [instance1, instance2, ...]

如果我这样做

del a[1]

instance2已从列表中删除,但是instance2 desctructor方法被调用了吗?

instance2 is removed from list, but is instance2 desctructor method called?

我对此感兴趣,因为我的代码使用了大量内存,并且需要释放内存以从列表中删除实例.

I'm interested in this because my code uses a lot of memory and I need to free memory deleting instances from a list.

推荐答案

来自c ++之类的语言(就像我所做的那样),这往往是许多人在第一次学习Python时很难理解的主题.

Coming from a language like c++ (as I did), this tends to be a subject many people find difficult to grasp when first learning Python.

底线是这样的:执行del XXX时,您永远不会*使用del删除对象.您仅删除对象引用.但是,在实践中,假设没有对instance2对象的其他引用,将其从列表中删除将根据需要释放内存.

The bottomline is this: when you do del XXX, you are never* deleting an object when you use del. You are only deleting an object reference. However, in practice, assuming there are no other references laying about to the instance2 object, deleting it from your list will free the memory as you desire.

如果您不了解对象和对象引用之间的区别,请继续阅读.

If you don't understand the difference between an object and an object reference, read on.

您可能熟悉通过引用或值将参数传递给函数的概念.但是,Python的处理方式有所不同.参数始终由对象引用传递.阅读此文章,以获取有关此含义的有用解释.

You are likely familiar with the concept of passing arguments to a function by reference, or by value. However, Python does things differently. Arguments are always passed by object reference. Read this article for a helpful explanation of what this means.

总结:这意味着,当您将变量传递给函数时,既没有传递变量值的副本(按值传递),也没有传递对象本身,即传递对象的地址.内存中的值.您正在传递间接引用内存中保存的值的名称对象.

To summarize: this means that when you pass a variable to a function, you are not passing a copy of the value of the variable (pass by value), nor are you passing the object itself - i.e., the address of the value in memory. You are passing the name-object that indirectly refers to the value held in memory.

好,我告诉你.

说你这样做:

def deleteit(thing):
    del thing

mylist = [1,2,3]
deleteit(mylist)

...您认为会发生什么? mylist是否已从全局名称空间中删除?

...what do you think will happen? Has mylist been deleted from the global namespace?

答案是否定的:

assert mylist # No error

原因是,当您在deleteit函数中执行del thing时,仅删除了该对象的本地对象引用.该对象引用仅存在于函数内部.作为侧边栏,您可能会问:是否可以在函数内部从全局名称空间中删除对象引用?答案是肯定的,但是您必须首先声明对象引用是全局名称空间的一部分:

The reason is that when you do del thing in the deleteit function, you are only deleting a local object reference to the object. That object reference exists ONLY inside of the function. As a sidebar, you might ask: is it possible to delete an object reference from the global namespace while inside a function? The answer is yes, but you have to declare the object reference to be part of the global namespace first:

def deletemylist():
    global mylist
    del mylist

mylist = [1,2,3]
deletemylist()
assert mylist #ERROR, as expected

将它们放在一起

现在回到您的原始问题.在ANY名称空间中执行以下操作时:

Putting it all together

Now to get back to your original question. When, in ANY namespace, you do this:

del XXX

...您尚未删除由XXX表示的对象.你不能那样做.您只删除了对象引用 XXX,它引用了内存中的某些对象.对象本身由 Python内存管理器管理.这是一个非常重要的区别.

...you have NOT deleted the object signified by XXX. You CAN'T do that. You have only deleted the object reference XXX, which refers to some object in memory. The object itself is managed by the Python memory manager. This is a very important distinction.

请注意,因此,当您覆盖某些对象的__del__方法时,该方法将在删除 对象 时调用(不是对象引用!) :

Note that as a consequence, when you override the __del__ method of some object, which gets called when the object is deleted (NOT the object reference!):

class MyClass():
    def __del__(self):
        print(self, "deleted")
        super().__del__()

m = MyClass()
del m

... __del__方法中的print语句不一定在执行del m之后立即发生.它仅在对象本身被删除的时间点发生,而这取决于您.这取决于Python内存管理器.删除所有命名空间中的所有对象引用后,最终将执行__del__方法.但不一定立即.

...the print statement inside the __del__ method does not necessarily occur immediately after you do del m. It only occurs at the point in time the object itself is deleted, and that is not up to you. It is up to the Python memory manager. When all object references in all the namespaces have been deleted, the __del__ method will eventually be executed. But not necessarily immediately.

当删除对象引用作为列表的一部分时,也是如此,就像原始示例一样.当您执行del a[1]时,仅删除对由a[1]表示的对象的对象引用,并且该对象的__del__方法可能会立即调用,也可能不会立即调用(尽管如前所述,最终它将被调用一次)不再有对该对象的引用,并且该对象是由内存管理器进行垃圾回收的).

The same is true when you delete an object reference that is part of a list, like in the original example. When you do del a[1], only the object reference to the object signified by a[1] is deleted, and the __del__ method of that object may or may not be called immediately (though as stated before, it will eventually be called once there are no more references to the object, and the object is garbage collected by the memory manager).

因此,不建议您将要在del mything上立即发生的事情放在__del__方法中,因为这样可能不会发生.

As a result of this, it is not recommended that you put things in the __del__ method that you want to happen immediately upon del mything, because it may not happen that way.

*我相信永远不会.不可避免地会有人拒绝我的回答,并留下评论讨论该规则的例外情况.但是,什么.

*I believe it is never. Inevitably someone will likely downvote my answer and leave a comment discussing the exception to the rule. But whatevs.

这篇关于从列表中调用元素的析构函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆