Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd804c6c

Browse files
committed
gh-75459: Doc: C API: Improve object life cycle documentation
* Add "cyclic isolate" to the glossary. * Add a new "Object Life Cycle" page. * Illustrate the order of life cycle functions. * Document `PyObject_CallFinalizer` and `PyObject_CallFinalizerFromDealloc`. * `PyObject_Init` does not call `tp_init`. * `PyObject_New`: * also initializes the memory * does not call `tp_alloc`, `tp_new`, or `tp_init` * should not be used for GC-enabled objects * memory must be freed by `PyObject_Free` * `PyObject_GC_New` memory must be freed by `PyObject_GC_Del`. * Warn that garbage collector functions can be called from any thread. * `tp_finalize` and `tp_clear`: * Only called when there's a cyclic isolate. * Only one object in the cyclic isolate is finalized/cleared at a time. * Clearly warn that they might not be called. * They can optionally be manually called from `tp_dealloc` (via `PyObject_CallFinalizerFromDealloc` in the case of `tp_finalize`). * `tp_finalize`: * Reference `object.__del__`. * The finalizer can resurrect the object. * Suggest `PyErr_GetRaisedException` and `PyErr_SetRaisedException` instead of the deprecated `PyErr_Fetch` and `PyErr_Restore` functions. * Add links to `PyErr_GetRaisedException` and `PyErr_SetRaisedException`. * Suggest using `PyErr_WriteUnraisable` if an exception is raised during finalization. * Rename the example function from `local_finalize` to `foo_finalize` for consistency with the `tp_dealloc` documentation and as a hint that the name isn't special. * Minor wording and sylistic tweaks. * Warn that `tp_finalize` can be called during shutdown.
1 parentda8673d commitd804c6c

File tree

9 files changed

+386
-65
lines changed

9 files changed

+386
-65
lines changed

‎.github/workflows/reusable-docs.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,12 @@ jobs:
8080
runs-on:ubuntu-latest
8181
timeout-minutes:60
8282
steps:
83+
-name:'Install Dependencies'
84+
run:|
85+
sudo apt-get update &&
86+
sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
87+
graphviz \
88+
;
8389
-uses:actions/checkout@v4
8490
-name:'Set up Python'
8591
uses:actions/setup-python@v5

‎.readthedocs.yml

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,26 @@ build:
1111
os:ubuntu-24.04
1212
tools:
1313
python:"3"
14+
apt_packages:
15+
-graphviz
16+
jobs:
17+
post_checkout:
18+
# https://docs.readthedocs.io/en/stable/build-customization.html#cancel-build-based-on-a-condition
19+
#
20+
# Cancel building pull requests when there aren't changes in the Doc directory.
21+
#
22+
# If there are no changes (git diff exits with 0) we force the command to return with 183.
23+
# This is a special exit code on Read the Docs that will cancel the build immediately.
24+
-|
25+
if [ "$READTHEDOCS_VERSION_TYPE" = "external" ] && [ "$(git diff --quiet origin/main -- Doc/ .readthedocs.yml; echo $?)" -eq 0 ];
26+
then
27+
echo "No changes to Doc/ - exiting the build.";
28+
exit 183;
29+
fi
1430
15-
commands:
16-
# https://docs.readthedocs.io/en/stable/build-customization.html#cancel-build-based-on-a-condition
17-
#
18-
# Cancel building pull requests when there aren't changes in the Doc directory.
19-
#
20-
# If there are no changes (git diff exits with 0) we force the command to return with 183.
21-
# This is a special exit code on Read the Docs that will cancel the build immediately.
22-
-|
23-
if [ "$READTHEDOCS_VERSION_TYPE" = "external" ] && [ "$(git diff --quiet origin/main -- Doc/ .readthedocs.yml; echo $?)" -eq 0 ];
24-
then
25-
echo "No changes to Doc/ - exiting the build.";
26-
exit 183;
27-
fi
28-
29-
-asdf plugin add uv
30-
-asdf install uv latest
31-
-asdf global uv latest
32-
-make -C Doc venv html
33-
-mkdir _readthedocs
34-
-mv Doc/build/html _readthedocs/html
35-
31+
-asdf plugin add uv
32+
-asdf install uv latest
33+
-asdf global uv latest
34+
-make -C Doc venv html
35+
-mkdir _readthedocs
36+
-mv Doc/build/html _readthedocs/html

‎Doc/c-api/allocation.rst

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ Allocating Objects on the Heap
1818
reference. Returns the initialized object. If *type* indicates that the
1919
object participates in the cyclic garbage detector, it is added to the
2020
detector's set of observed objects. Other fields of the object are not
21-
affected.
21+
initialized. Specifically, this function does **not** call the object's
22+
:meth:`~object.__init__` method (:c:member:`~PyTypeObject.tp_init` slot).
2223
2324
2425
.. c:function:: PyVarObject* PyObject_InitVar(PyVarObject *op, PyTypeObject *type, Py_ssize_t size)
@@ -29,27 +30,44 @@ Allocating Objects on the Heap
2930
3031
..c:macro:: PyObject_New(TYPE, typeobj)
3132
32-
Allocate a new Python object using the C structure type *TYPE*
33-
and the Python type object *typeobj* (``PyTypeObject*``).
34-
Fields not defined by the Python object header are not initialized.
35-
The caller will own the only reference to the object
36-
(i.e. its reference count will be one).
37-
The size of the memory allocation is determined from the
38-
:c:member:`~PyTypeObject.tp_basicsize` field of the type object.
33+
Calls:c:func:`PyObject_Malloc` to allocate memory for a new Python object
34+
using the C structure type *TYPE* and the Python type object *typeobj*
35+
(``PyTypeObject*``), then initializes the memory like
36+
:c:func:`PyObject_Init`. The caller will own the only reference to the
37+
object (i.e. its reference count will be one). The size of the memory
38+
allocation is determined from the :c:member:`~PyTypeObject.tp_basicsize`
39+
field of the type object.
40+
41+
This does not call :c:member:`~PyTypeObject.tp_alloc`,
42+
:c:member:`~PyTypeObject.tp_new` (:meth:`~object.__new__`), or
43+
:c:member:`~PyTypeObject.tp_init` (:meth:`~object.__init__`).
44+
45+
This should not be used for objects with :c:macro:`Py_TPFLAGS_HAVE_GC` set
46+
in :c:member:`~PyTypeObject.tp_flags`; use :c:macro:`PyObject_GC_New`
47+
instead.
48+
49+
Memory allocated by this function must be freed with:c:func:`PyObject_Free`.
3950
4051
4152
..c:macro:: PyObject_NewVar(TYPE, typeobj, size)
4253
43-
Allocate a new Python object using the C structure type *TYPE* and the
44-
Python type object *typeobj* (``PyTypeObject*``).
45-
Fields not defined by the Python object header
46-
are not initialized. The allocated memory allows for the *TYPE* structure
47-
plus *size* (``Py_ssize_t``) fields of the size
48-
given by the :c:member:`~PyTypeObject.tp_itemsize` field of
49-
*typeobj*. This is useful for implementing objects like tuples, which are
50-
able to determine their size at construction time. Embedding the array of
51-
fields into the same allocation decreases the number of allocations,
52-
improving the memory management efficiency.
54+
Like:c:macro:`PyObject_New` except:
55+
56+
* It allocates enough memory for the *TYPE* structure plus *size*
57+
(``Py_ssize_t``) fields of the size given by the
58+
:c:member:`~PyTypeObject.tp_itemsize` field of *typeobj*.
59+
* The memory is initialized like :c:func:`PyObject_InitVar`.
60+
61+
This is useful for implementing objects like tuples, which are able to
62+
determine their size at construction time. Embedding the array of fields
63+
into the same allocation decreases the number of allocations, improving the
64+
memory management efficiency.
65+
66+
This should not be used for objects with :c:macro:`Py_TPFLAGS_HAVE_GC` set
67+
in :c:member:`~PyTypeObject.tp_flags`; use :c:macro:`PyObject_GC_NewVar`
68+
instead.
69+
70+
Memory allocated by this function must be freed with:c:func:`PyObject_Free`.
5371
5472
5573
..c:function::voidPyObject_Del(void *op)

‎Doc/c-api/gcsupport.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,17 @@ rules:
5757
Analogous to:c:macro:`PyObject_New` but for container objects with the
5858
:c:macro:`Py_TPFLAGS_HAVE_GC` flag set.
5959

60+
Memory allocated by this function must be freed with
61+
:c:func:`PyObject_GC_Del`.
62+
6063
..c:macro:: PyObject_GC_NewVar(TYPE, typeobj, size)
6164
6265
Analogous to:c:macro:`PyObject_NewVar` but for container objects with the
6366
:c:macro:`Py_TPFLAGS_HAVE_GC` flag set.
6467

68+
Memory allocated by this function must be freed with
69+
:c:func:`PyObject_GC_Del`.
70+
6571
..c:function:: PyObject*PyUnstable_Object_GC_NewWithExtraData(PyTypeObject *type, size_t extra_size)
6672
6773
Analogous to:c:macro:`PyObject_GC_New` but allocates *extra_size*
@@ -73,6 +79,9 @@ rules:
7379
The extra data will be deallocated with the object, but otherwise it is
7480
not managed by Python.
7581
82+
Memory allocated by this function must be freed with
83+
:c:func:`PyObject_GC_Del`.
84+
7685
.. warning::
7786
The function is marked as unstable because thefinal mechanism
7887
for reserving extra data after an instance is not yet decided.

‎Doc/c-api/lifecycle.rst

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
..highlight::c
2+
3+
.. _life-cycle:
4+
5+
Object Life Cycle
6+
=================
7+
8+
Stages
9+
------
10+
11+
The following is an illustration of the stages of life of an object. Arrows
12+
indicate a "happens before" relationship. Octagons indicate functions specific
13+
to:ref:`garbage collection support<supporting-cycle-detection>`.
14+
15+
..digraph::callorder
16+
17+
graph [
18+
fontname="svg"
19+
fontsize=10.0
20+
layout="dot"
21+
ranksep=0.25
22+
]
23+
node [
24+
fontname="Courier"
25+
fontsize=10.0
26+
]
27+
edge [
28+
fontname="Times-Italic"
29+
fontsize=10.0
30+
]
31+
32+
"start" [fontname="Times-Italic" shape=plain label=< start > style=invis]
33+
"tp_alloc" [href="typeobj.html#c.PyTypeObject.tp_alloc" target="_top"]
34+
"tp_new" [href="typeobj.html#c.PyTypeObject.tp_new" target="_top"]
35+
"tp_init" [href="typeobj.html#c.PyTypeObject.tp_init" target="_top"]
36+
{
37+
rank="same"
38+
"alive" [
39+
fontname="Times-Italic"
40+
label=<alive, ref count &gt; 0>
41+
shape=box
42+
]
43+
"tp_traverse" [
44+
href="typeobj.html#c.PyTypeObject.tp_traverse"
45+
shape=octagon
46+
target="_top"
47+
]
48+
}
49+
"tp_finalize" [
50+
href="typeobj.html#c.PyTypeObject.tp_finalize"
51+
shape=octagon
52+
target="_top"
53+
]
54+
"tp_clear" [
55+
href="typeobj.html#c.PyTypeObject.tp_clear"
56+
shape=octagon
57+
target="_top"
58+
]
59+
"ref0" [
60+
fontname="Times-Italic"
61+
label=<ref count == 0>
62+
ordering="in"
63+
shape=box
64+
]
65+
"tp_dealloc" [href="typeobj.html#c.PyTypeObject.tp_dealloc" target="_top"]
66+
"tp_free" [href="typeobj.html#c.PyTypeObject.tp_free" target="_top"]
67+
68+
"start" -> "tp_alloc"
69+
"tp_alloc" -> "tp_new"
70+
"tp_new" -> "tp_init"
71+
"tp_init" -> "alive"
72+
"tp_traverse" -> "alive"
73+
"alive" -> "tp_traverse"
74+
"alive" -> "tp_clear" [label=< cyclic <br/>isolate >]
75+
"alive" -> "tp_finalize" [
76+
dir="back"
77+
label=< resurrected >
78+
]
79+
"alive" -> "tp_finalize" [label=< cyclic <br/>isolate >]
80+
"tp_finalize" -> "tp_clear"
81+
"tp_finalize" -> "ref0"
82+
"tp_clear" -> "ref0"
83+
"tp_clear" -> "tp_dealloc" [
84+
dir="back"
85+
label=< optional<br/>direct call >
86+
]
87+
"alive" -> "ref0"
88+
"ref0" -> "tp_dealloc"
89+
"tp_finalize" -> "tp_dealloc" [
90+
dir="back"
91+
href="lifecycle.html#c.PyObject_CallFinalizerFromDealloc"
92+
label=<
93+
<table border="0" cellborder="0" cellpadding="0" cellspacing="0">
94+
<tr>
95+
<td rowspan="4"> </td>
96+
<td align="left">optional call to</td>
97+
<td rowspan="4"> </td>
98+
</tr>
99+
<tr>
100+
<td align="left"><font face="Courier">PyObject_Call</font></td>
101+
</tr>
102+
<tr>
103+
<td align="left"><font face="Courier">FinalizerFrom</font></td>
104+
</tr>
105+
<tr><td align="left"><font face="Courier">Dealloc</font></td></tr>
106+
</table>
107+
>
108+
target="_top"
109+
]
110+
"tp_dealloc" -> "tp_free" [label=< directly calls >]
111+
112+
Explanation:
113+
114+
*:c:member:`~PyTypeObject.tp_alloc`,:c:member:`~PyTypeObject.tp_new`, and
115+
:c:member:`~PyTypeObject.tp_init` are called to allocate memory for a new
116+
object and initialize the object.
117+
* If the reference count for an object drops to 0,
118+
:c:member:`~PyTypeObject.tp_dealloc` is called to destroy the object.
119+
*:c:member:`~PyTypeObject.tp_dealloc` can optionally call
120+
:c:member:`~PyTypeObject.tp_finalize` (if non-``NULL``) via
121+
:c:func:`PyObject_CallFinalizerFromDealloc` if it wishes to reuse that code
122+
to help with object destruction.
123+
*:c:member:`~PyTypeObject.tp_finalize` may increase the object's reference
124+
count, halting the destruction. The object is said to be resurrected.
125+
*:c:member:`~PyTypeObject.tp_dealloc` can optionally call
126+
:c:member:`~PyTypeObject.tp_clear` (if non-``NULL``) if it wishes to reuse
127+
that code to help with object destruction.
128+
* When:c:member:`~PyTypeObject.tp_dealloc` finishes object destruction, it
129+
directly calls:c:member:`~PyTypeObject.tp_free` to deallocate the memory.
130+
131+
If the object is marked as supporting garbage collection (the
132+
:c:macro:`Py_TPFLAGS_HAVE_GC` flag is set in
133+
:c:member:`~PyTypeObject.tp_flags`), the following stages are also possible:
134+
135+
* The garbage collector occasionally calls
136+
:c:member:`~PyTypeObject.tp_traverse` to identify:term:`cyclic isolates
137+
<cyclic isolate>`.
138+
* When the garbage collector discovers a cyclic isolate, it finalizes one of
139+
the objects in the group by calling its:c:member:`~PyTypeObject.tp_finalize`
140+
function. This repeats until the cyclic isolate doesn't exist or all of the
141+
objects have been finalized.
142+
* The:c:member:`~PyTypeObject.tp_finalize` function can optionally increase
143+
the object's reference count, causing it (and other objects it references) to
144+
become resurrected and no longer a member of a cyclic isolate.
145+
* When the garbage collector discovers a cyclic isolate and all of the objects
146+
in the group have already been finalized, the garbage collector clears one of
147+
the objects in the group by calling its:c:member:`~PyTypeObject.tp_clear`
148+
function. This repeats until the cyclic isolate doesn't exist or all of the
149+
objects have been cleared.
150+
151+
152+
Functions
153+
---------
154+
155+
To allocate and free memory, see:ref:`Allocating Objects on the Heap
156+
<allocating-objects>`.
157+
158+
159+
..c:function::voidPyObject_CallFinalizer(PyObject *op)
160+
161+
Calls the object's finalizer (:c:member:`~PyTypeObject.tp_finalize`) if it
162+
has not already been called.
163+
164+
165+
.. c:function:: int PyObject_CallFinalizerFromDealloc(PyObject *op)
166+
167+
Calls the object's finalizer (:c:member:`~PyTypeObject.tp_finalize`) if it
168+
has not already been called. This function is intended to be called at the
169+
beginning of the object's destructor (:c:member:`~PyTypeObject.tp_dealloc`).
170+
The object's reference count must already be 0. If the object's finalizer
171+
increases the object's reference count, the object is resurrected and this
172+
function returns -1; no further destruction should happen. Otherwise, this
173+
function returns 0 and destruction can continue normally.

‎Doc/c-api/objimpl.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ object types.
1212
..toctree::
1313

1414
allocation.rst
15+
lifecycle.rst
1516
structures.rst
1617
typeobj.rst
1718
gcsupport.rst

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp