I have something like that:
a = [instance1, instance2, ...]
if I do a
del a[1]
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.
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.
The bottomline is this: when you do
del XXX
, you are never* deleting an object when you usedel
. You are only deleting an object reference. However, in practice, assuming there are no other references laying about to theinstance2
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: Pass by value, or pass by reference?
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.
What does this have to do with
del
...?Well, I'll tell you.
Say you do this:
...what do you think will happen? Has
mylist
been deleted from the global namespace?The answer is NO:
The reason is that when you do
del thing
in thedeleteit
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:Putting it all together
Now to get back to your original question. When, in ANY namespace, you do this:
...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.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!):...the print statement inside the
__del__
method does not necessarily occur immediately after you dodel 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.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 bya[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).As a result of this, it is not recommended that you put things in the
__del__
method that you want to happen immediately upondel 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.
No. Calling
del
on a list element only removes a reference to an object from the list, it doesn't do anything (explicitly) to the object itself. However: If the reference in the list was the last one referring to the object, the object can now be destroyed and recycled. I think that the "normal" CPython implementation will immediately destroy and recycle the object, other variants' behaviour can vary.If your object is resource-heavy and you want to be sure that the resources are freed correctly, use the
with()
construct. It's very easy to leak resources when relying on destructors. See this SO post for more details.