__del__ is not called after creating a new reference
Terry Reedy
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
> says:
>
> object.__del__(self)
> ...
> 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):
> print("DEL")
> global X
> X = self
> C()
> print(X)
> X = 0
> print(X)
>
> shows that __del__ is called only once, it is not called again after "X = 0":
>
> DEL
> <__main__.C object at 0x7f067695f4a8>
> 0
>
> (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;
> _Py_NewReference(self);
> 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))
> return;
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.
>
> Oleg.
>
--
Terry Jan Reedy
More information about the Python-list
mailing list