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

gh-134160: Use multi-phase init in documentation examples#134296

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
neonene wants to merge20 commits intopython:main
base:main
Choose a base branch
Loading
fromneonene:multi
Open
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
20 commits
Select commitHold shift + click to select a range
8d8b366
Update docs
neoneneMay 19, 2025
88c5f3f
Don't change an unrelated example
neoneneMay 20, 2025
a4ade5c
Apply suggestions from code review
neoneneMay 21, 2025
d6c42e2
ditto
neoneneMay 21, 2025
97eae13
Suggested module names
neoneneMay 21, 2025
8ae6bae
Avoid modernization
neoneneMay 21, 2025
bc78288
typo
neoneneMay 21, 2025
c3ab022
Correction: "error"
neoneneMay 21, 2025
d65303c
Rephrase warning
neoneneMay 21, 2025
aec6781
keywdarg_module
neoneneMay 21, 2025
7dfd5ad
Update Doc/extending/extending.rst
neoneneMay 22, 2025
f7c72dd
Indicate xxlimited
neoneneMay 22, 2025
c84638c
Add seealso to index
neoneneMay 22, 2025
4e59e88
Update Doc/extending/embedding.rst
neoneneMay 22, 2025
d68e3e3
ditto (for copy-paste)
neoneneMay 22, 2025
f6465bd
Shrink slots
neoneneMay 22, 2025
1a65816
Remove module states
neoneneMay 22, 2025
a83e266
Correction: "SpamError"
neoneneMay 22, 2025
2d10958
Add a Py_mod_multiple_interpreters slot
neoneneMay 22, 2025
a28e67c
Cancel the prvious addition as needless
neoneneMay 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletionsDoc/c-api/intro.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -127,15 +127,16 @@ complete listing.
item defined in the module file. Example::

static struct PyModuleDef spam_module = {
PyModuleDef_HEAD_INIT,
.m_base =PyModuleDef_HEAD_INIT,
.m_name = "spam",
.m_size = 0,
...
};

PyMODINIT_FUNC
PyInit_spam(void)
{
returnPyModule_Create(&spam_module);
returnPyModuleDef_Init(&spam_module);
}


Expand Down
12 changes: 7 additions & 5 deletionsDoc/extending/embedding.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -245,21 +245,23 @@ Python extension. For example::
return PyLong_FromLong(numargs);
}

static PyMethodDefEmbMethods[] = {
static PyMethodDefemb_module_methods[] = {
{"numargs", emb_numargs, METH_VARARGS,
"Return the number of arguments received by the process."},
{NULL, NULL, 0, NULL}
};

static PyModuleDef EmbModule = {
PyModuleDef_HEAD_INIT, "emb", NULL, -1, EmbMethods,
NULL, NULL, NULL, NULL
struct PyModuleDef emb_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "emb",
.m_size = 0,
.m_methods = emb_module_methods,
};

static PyObject*
PyInit_emb(void)
{
returnPyModule_Create(&EmbModule);
returnPyModuleDef_Init(&emb_module);
}

Insert the above code just above the :c:func:`main` function. Also, insert the
Expand Down
165 changes: 93 additions & 72 deletionsDoc/extending/extending.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -208,26 +208,38 @@ usually declare a static object variable at the beginning of your file::

static PyObject *SpamError;

and initialize it in your module's initialization function (:c:func:`!PyInit_spam`)
and initialize it in the module's :c:data:`Py_mod_exec` function
(:c:func:`!spam_module_exec`)

with an exception object::

PyMODINIT_FUNC
PyInit_spam(void)
static int
spam_module_exec(PyObject *m)
{
PyObject *m;

m = PyModule_Create(&spammodule);
if (m == NULL)
return NULL;

SpamError = PyErr_NewException("spam.error", NULL, NULL);
if (PyModule_AddObjectRef(m, "error", SpamError) < 0) {
Py_CLEAR(SpamError);
Py_DECREF(m);
return NULL;
if (PyModule_AddObjectRef(m, "SpamError", SpamError) < 0) {
return -1;
}

return m;
return 0;
}

static PyModuleDef_Slot spam_module_slots[] = {
{Py_mod_exec, spam_module_exec},
{0, NULL}
};

static struct PyModuleDef spam_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "spam",
.m_size = 0, // non-negative
.m_slots = spam_module_slots,
};

PyMODINIT_FUNC
PyInit_spam(void)
{
return PyModuleDef_Init(&spam_module);
}

Note that the Python name for the exception object is :exc:`!spam.error`. The
Expand DownExpand Up@@ -318,7 +330,7 @@ The Module's Method Table and Initialization Function
I promised to show how :c:func:`!spam_system` is called from Python programs.
First, we need to list its name and address in a "method table"::

static PyMethodDefSpamMethods[] = {
static PyMethodDefspam_methods[] = {
...
{"system", spam_system, METH_VARARGS,
"Execute a shell command."},
Expand All@@ -343,13 +355,10 @@ function.

The method table must be referenced in the module definition structure::

static struct PyModuleDef spammodule = {
PyModuleDef_HEAD_INIT,
"spam", /* name of module */
spam_doc, /* module documentation, may be NULL */
-1, /* size of per-interpreter state of the module,
or -1 if the module keeps state in global variables. */
SpamMethods
static struct PyModuleDef spam_module = {
...
.m_methods = spam_methods,
...
};

This structure, in turn, must be passed to the interpreter in the module's
Expand All@@ -360,23 +369,17 @@ only non-\ ``static`` item defined in the module file::
PyMODINIT_FUNC
PyInit_spam(void)
{
returnPyModule_Create(&spammodule);
returnPyModuleDef_Init(&spam_module);
}

Note that :c:macro:`PyMODINIT_FUNC` declares the function as ``PyObject *`` return type,
declares any special linkage declarations required by the platform, and for C++
declares the function as ``extern "C"``.

When the Python program imports module :mod:`!spam` for the first time,
:c:func:`!PyInit_spam` is called. (See below for comments about embedding Python.)
It calls :c:func:`PyModule_Create`, which returns a module object, and
inserts built-in function objects into the newly created module based upon the
table (an array of :c:type:`PyMethodDef` structures) found in the module definition.
:c:func:`PyModule_Create` returns a pointer to the module object
that it creates. It may abort with a fatal error for
certain errors, or return ``NULL`` if the module could not be initialized
satisfactorily. The init function must return the module object to its caller,
so that it then gets inserted into ``sys.modules``.
:c:func:`!PyInit_spam` is called when each interpreter imports its module
:mod:`!spam` for the first time. (See below for comments about embedding Python.)
A pointer to the module definition must be returned via :c:func:`PyModuleDef_Init`,
so that the import machinery can create the module and store it in ``sys.modules``.

When embedding Python, the :c:func:`!PyInit_spam` function is not called
automatically unless there's an entry in the :c:data:`PyImport_Inittab` table.
Expand DownExpand Up@@ -433,24 +436,18 @@ optionally followed by an import of the module::

.. note::

Removing entries from ``sys.modules`` or importing compiled modules into
If you declare a global variable or a local static one, the module can
cause the same problems as the legacy single-phase initialization when
removing entries from ``sys.modules`` or importing compiled modules into
multiple interpreters within a process (or following a :c:func:`fork` without an
intervening :c:func:`exec`) can create problems for some extension modules.
Extension module authors should exercise caution when initializing internal data
structures.
intervening :c:func:`exec`). In this case, at least the module should
stop supporting subinterpreters through a :c:type:`PyModuleDef_Slot`
(:c:data:`Py_mod_multiple_interpreters`).

A more substantial example module is included in the Python source distribution
as :file:`Modules/xxmodule.c`. This file may be used as a template or simply
as :file:`Modules/xxlimited.c`. This file may be used as a template or simply
read as an example.

.. note::

Unlike our ``spam`` example, ``xxmodule`` uses *multi-phase initialization*
(new in Python 3.5), where a PyModuleDef structure is returned from
``PyInit_spam``, and creation of the module is left to the import machinery.
For details on multi-phase initialization, see :PEP:`489`.


.. _compilation:

Compilation and Linkage
Expand DownExpand Up@@ -790,18 +787,17 @@ Philbrick (philbrick@hks.com)::
{NULL, NULL, 0, NULL} /* sentinel */
};

static struct PyModuleDef keywdargmodule = {
PyModuleDef_HEAD_INIT,
"keywdarg",
NULL,
-1,
keywdarg_methods
static struct PyModuleDef keywdarg_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "keywdarg",
.m_size = 0,
.m_methods = keywdarg_methods,
};

PyMODINIT_FUNC
PyInit_keywdarg(void)
{
returnPyModule_Create(&keywdargmodule);
returnPyModuleDef_Init(&keywdarg_module);
}


Expand DownExpand Up@@ -1262,29 +1258,41 @@ The ``#define`` is used to tell the header file that it is being included in the
exporting module, not a client module. Finally, the module's initialization
function must take care of initializing the C API pointer array::

PyMODINIT_FUNC
PyInit_spam(void)
static int
spam_module_exec(PyObject *m)
{
PyObject *m;
static void *PySpam_API[PySpam_API_pointers];
PyObject *c_api_object;

m = PyModule_Create(&spammodule);
if (m == NULL)
return NULL;

/* Initialize the C API pointer array */
PySpam_API[PySpam_System_NUM] = (void *)PySpam_System;

/* Create a Capsule containing the API pointer array's address */
c_api_object = PyCapsule_New((void *)PySpam_API, "spam._C_API", NULL);

if (PyModule_Add(m, "_C_API", c_api_object) < 0) {
Py_DECREF(m);
return NULL;
return -1;
}

return m;
return 0;
}

static PyModuleDef_Slot spam_module_slots[] = {
{Py_mod_exec, spam_module_exec},
{0, NULL}
};

static struct PyModuleDef spam_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "spam",
.m_size = 0,
.m_slots = spam_module_slots,
};

PyMODINIT_FUNC
PyInit_spam(void)
{
return PyModuleDef_Init(&spam_module);
}

Note that ``PySpam_API`` is declared ``static``; otherwise the pointer
Expand DownExpand Up@@ -1345,18 +1353,31 @@ All that a client module must do in order to have access to the function
:c:func:`!PySpam_System` is to call the function (or rather macro)
:c:func:`!import_spam` in its initialization function::

PyMODINIT_FUNC
PyInit_client(void)
static int
client_module_exec(PyObject *m)
{
PyObject *m;

m = PyModule_Create(&clientmodule);
if (m == NULL)
return NULL;
if (import_spam() < 0)
returnNULL;
return-1;
/* additional initialization can happen here */
return m;
return 0;
}

static PyModuleDef_Slot client_module_slots[] = {
{Py_mod_exec, client_module_exec},
{0, NULL}
};

static struct PyModuleDef client_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "client",
.m_size = 0,
.m_slots = client_module_slots,
};

PyMODINIT_FUNC
PyInit_client(void)
{
return PyModuleDef_Init(&client_module);
}

The main disadvantage of this approach is that the file :file:`spammodule.h` is
Expand Down
4 changes: 4 additions & 0 deletionsDoc/extending/index.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -49,6 +49,10 @@ assistance from third party tools. It is intended primarily for creators
of those tools, rather than being a recommended way to create your own
C extensions.

.. seealso::

:pep:`489` -- Multi-phase extension module initialization

.. toctree::
:maxdepth: 2
:numbered:
Expand Down
25 changes: 9 additions & 16 deletionsDoc/extending/newtypes_tutorial.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -171,18 +171,17 @@ implementation provided by the API function :c:func:`PyType_GenericNew`. ::
.tp_new = PyType_GenericNew,

Everything else in the file should be familiar, except for some code in
:c:func:`!PyInit_custom`::
:c:func:`!custom_module_exec`::

if (PyType_Ready(&CustomType) < 0)
return;
return -1;

This initializes the :class:`!Custom` type, filling in a number of members
to the appropriate default values, including :c:member:`~PyObject.ob_type` that we initially
set to ``NULL``. ::

if (PyModule_AddObjectRef(m, "Custom", (PyObject *) &CustomType) < 0) {
Py_DECREF(m);
return NULL;
return -1;
}

This adds the type to the module dictionary. This allows us to create
Expand DownExpand Up@@ -875,27 +874,21 @@ but let the base class handle it by calling its own :c:member:`~PyTypeObject.tp_
The :c:type:`PyTypeObject` struct supports a :c:member:`~PyTypeObject.tp_base`
specifying the type's concrete base class. Due to cross-platform compiler
issues, you can't fill that field directly with a reference to
:c:type:`PyList_Type`; it should be donelaterin themodule initialization
:c:type:`PyList_Type`; it should be done in the:c:data:`Py_mod_exec`
function::

PyMODINIT_FUNC
PyInit_sublist(void)
static int
sublist_module_exec(PyObject *m)
{
PyObject* m;
SubListType.tp_base = &PyList_Type;
if (PyType_Ready(&SubListType) < 0)
return NULL;

m = PyModule_Create(&sublistmodule);
if (m == NULL)
return NULL;
return -1;

if (PyModule_AddObjectRef(m, "SubList", (PyObject *) &SubListType) < 0) {
Py_DECREF(m);
return NULL;
return -1;
}

returnm;
return0;
}

Before calling :c:func:`PyType_Ready`, the type structure must have the
Expand Down
Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp