Reputation: 8030
Surfing on the internet (here) I found that there are some problems to collect objects with __del__
method for the garbage collector.
My doubt is simple: why?
According to the documentation:
Objects that have
__del__()
methods and are part of a reference cycle cause the entire reference cycle to be uncollectable, including objects not necessarily in the cycle but reachable only from it. Python doesn’t collect such cycles automatically because, in general, it isn’t possible for Python to guess a safe order in which to run the__del__()
methods.
Why is the __del__
method so problematic? What's the difference between an object that implements it and one which doesn't? It only destroys an instance.
Upvotes: 0
Views: 1125
Reputation: 154886
__del__
doesn't destroy an instance, it is automatically destroyed by the python runtime once its reference count reaches zero. __del__
allows you to hook into that process and perform additional actions, such as freeing external resources associated with the object.
The danger is that the additional action may even resurrect the object - for example, by storing it into a global container. In that case, the destruction is effectively cancelled (until the next time the object's reference count drops to zero). It is this scenario that causes the mere presence of __del__
to exclude the object from those governed by the cycle breaker (also known as the garbage collector). If the collector invoked __del__
on all objects in the cycle, and one of them decided to resurrect the object, this would need to resurrect the whole cycle - which is impossible since __del__
method of other cycle members have already been invoked, possibly causing permanent damage to their objects (e.g. by freeing external resources, as mentioned above).
If you only need to be notified of object's destruction, use weakref.ref
. If your object is associated with external resources that need freeing, implement a close
method and/or a context manager interface. There is almost never a legitimate reason to use __del__
.
Upvotes: 3