__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