__del__ is not called after creating a new reference
tjreedy at udel.edu
Fri Mar 17 11:11:54 EDT 2017
On 3/17/2017 10:54 AM, Oleg Nesterov wrote:
> I started to learn python a few days ago and I am trying to understand what
> __del__() actually does. https://docs.python.org/3/reference/datamodel.html
> Note that it is possible (though not recommended!) for the __del__()
> method to postpone destruction of the instance by creating a new
> reference to it.
If I understand the below, 'that persists after the function call'
should be added. Note that the function call itself 'creates a new
reference' by binding 'self' to the obj.
It may then be called at a later time when this new
> reference is deleted.
> However, this trivial test-case
> class C:
> def __del__(self):
> global X
> X = self
> X = 0
> shows that __del__ is called only once, it is not called again after "X = 0":
> <__main__.C object at 0x7f067695f4a8>
> (Just in case, I verified later that this object actually goes away and its
> memory is freed, so the problem is not that it still has a reference).
> I've cloned https://github.com/python/cpython.git and everything looks clear
> at first glance (but let me repeat that I am very new to python):
> PyObject_CallFinalizerFromDealloc() calls PyObject_CallFinalizer()
> which finally calls "__del__" method in slot_tp_finalize(), then it
> notices that "X = self" creates the new reference and does:
> /* tp_finalize resurrected it! Make it look like the original Py_DECREF
> * never happened.
> refcnt = self->ob_refcnt;
> self->ob_refcnt = refcnt;
> However, PyObject_CallFinalizer() also does _PyGC_SET_FINALIZED(self, 1)
> and that is why __del__ is not called again after "X = 0":
> /* tp_finalize should only be called once. */
> if (PyType_IS_GC(tp) && _PyGC_FINALIZED(self))
I suspect that this was added after the doc. If git has an annotate
function, you could check.
> The comment and the code are very explicit, so this does nt look like a
> bug in cpython.
> Probably the docs should be fixed?
> Or this code is actually wrong? The test-case works as documented if I
> remove _PyGC_SET_FINALIZED() in PyObject_CallFinalizer() or add another
> _PyGC_SET_FINALIZED(self, 0) into PyObject_CallFinalizerFromDealloc()
> after _Py_NewReference(self), but yes, yes, I understand that this is
> not correct and won't really help.
Terry Jan Reedy
More information about the Python-list