Issue33909
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) * ![]() |
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:01 | admin | set | github: 78090 |
| 2021-12-03 23:10:41 | iritkatriel | set | nosy:
+ 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:23 | methane | set | nosy:
+ methane messages: + msg320134 |
| 2018-06-20 08:23:24 | Eric.Wieser | create | |
