This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: PyObject_CallFinalizerFromDealloc is not referenced in any documentation
Type: Stage:
Components: Documentation Versions: Python 3.11, Python 3.10, Python 3.9
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: docs@python Nosy List: Eric.Wieser, docs@python, methane, pitrou
Priority: normal Keywords:

Created on 2018-06-20 08:23 by Eric.Wieser, last changed 2022-04-11 14:59 by admin.

Messages (2)
msg320036 - (view) Author: Eric Wieser (Eric.Wieser) * Date: 2018-06-20 08:23
PEP 442 states that:

> Two new C API functions are provided to ease calling of tp_finalize, especially from custom deallocators.

But it does not give the names of these functions, nor do any python docs I can discover.

From grepping for tp_finalize, it seems the functions in question are:

- PyObject_CallFinalizerFromDealloc 
- PyObject_CallFinalizer

It would be great if these could be documented, and perhaps even an example given of when it's appropriate to call each one.
msg320134 - (view) Author: Inada Naoki (methane) * (Python committer) Date: 2018-06-21 02:33
I think I can describe what two function does/for.
But I'm not good English writer.  Would you write document instead?

---

"Finalizer" is __del__ in Python and tp_finalize in C.

Calling finalizer requires some tricks, including avoiding call twice.
That is what PyObject_CallFinalizer() does.  Use it instead of call `type->tp_finalize(obj)` directly.

But finalizer is called from destructor (tp_dealloc) usually, and calling finalizer from destructor need more hack (e.g. temporary increment refcount).  This is what PyObject_CallFinalizerFromDealloc does.

Generally speaking, this API is used only when you want to use both of custom tp_dealloc and tp_finalize.  This is very rare because you can write cleanup code in tp_dealloc and skip using tp_finalize.

When you need really need both of tp_dealloc and tp_finalize, note that:

* Finalizer may resurrect the object.
* When the type is subclassed from Python, tp_finalize is called automatically.  You must not call PyObject_CallFinalizerFromDealloc then.

This is tp_dealloc of Future object in asyncio.  This object uses both of tp_dealloc and tp_finalize for compatibility with Future object implemented in pure Python.  This covers many edge cases of tp_dealloc.

```
static void
FutureObj_dealloc(PyObject *self)
{
    FutureObj *fut = (FutureObj *)self;

    if (Future_CheckExact(fut)) {
        /* When fut is subclass of Future, finalizer is called from
         * subtype_dealloc.
         */
        if (PyObject_CallFinalizerFromDealloc(self) < 0) {
            // resurrected.
            return;
        }
    }

    // Weakref callback and finalizer of other objects may start GC.
    // So you need to untrack this object from GC before calling PyObject_ClearWeakRefs()
    // or any Py_DECREF()s
    // Otherwise, GC will cause segfault because refcount of this object is 0.
    PyObject_GC_UnTrack(self);

    // Handle weakrefs
    if (fut->fut_weakreflist != NULL) {
        PyObject_ClearWeakRefs(self);
    }

    // Reuse tp_clear() for clearing all members.
    (void)FutureObj_clear(fut);

    // Free this object at last.
    Py_TYPE(fut)->tp_free(fut);
}
```
History
Date User Action Args
2022-04-11 14:59:01adminsetgithub: 78090
2021-12-03 23:10:41iritkatrielsetnosy: + pitrou

versions: + Python 3.9, Python 3.10, Python 3.11, - Python 3.4, Python 3.5, Python 3.6, Python 3.7, Python 3.8
2018-06-21 02:33:23methanesetnosy: + methane
messages: + msg320134
2018-06-20 08:23:24Eric.Wiesercreate