bpo-39161: Document multi-phase init modules under Py_NewInterpreter() (GH-17896)

\+ this also adds a stronger warning against sharing objects between (sub-)interpreters.



https://bugs.python.org/issue39161
This commit is contained in:
Petr Viktorin 2020-01-09 13:05:18 +01:00 committed by Miss Islington (bot)
parent f3e5e95669
commit 6c5d661342

View file

@ -1230,15 +1230,31 @@ function. You can create and destroy them using the following functions:
single: Py_FinalizeEx() single: Py_FinalizeEx()
single: Py_Initialize() single: Py_Initialize()
Extension modules are shared between (sub-)interpreters as follows: the first Extension modules are shared between (sub-)interpreters as follows:
time a particular extension is imported, it is initialized normally, and a
(shallow) copy of its module's dictionary is squirreled away. When the same * For modules using multi-phase initialization,
extension is imported by another (sub-)interpreter, a new module is initialized e.g. :c:func:`PyModule_FromDefAndSpec`, a separate module object is
and filled with the contents of this copy; the extension's ``init`` function is created and initialized for each interpreter.
not called. Note that this is different from what happens when an extension is Only C-level static and global variables are shared between these
imported after the interpreter has been completely re-initialized by calling module objects.
:c:func:`Py_FinalizeEx` and :c:func:`Py_Initialize`; in that case, the extension's
``initmodule`` function *is* called again. * For modules using single-phase initialization,
e.g. :c:func:`PyModule_Create`, the first time a particular extension
is imported, it is initialized normally, and a (shallow) copy of its
module's dictionary is squirreled away.
When the same extension is imported by another (sub-)interpreter, a new
module is initialized and filled with the contents of this copy; the
extension's ``init`` function is not called.
Objects in the module's dictionary thus end up shared across
(sub-)interpreters, which might cause unwanted behavior (see
`Bugs and caveats`_ below).
Note that this is different from what happens when an extension is
imported after the interpreter has been completely re-initialized by
calling :c:func:`Py_FinalizeEx` and :c:func:`Py_Initialize`; in that
case, the extension's ``initmodule`` function *is* called again.
As with multi-phase initialization, this means that only C-level static
and global variables are shared between these modules.
.. index:: single: close() (in module os) .. index:: single: close() (in module os)
@ -1264,14 +1280,16 @@ process, the insulation between them isn't perfect --- for example, using
low-level file operations like :func:`os.close` they can low-level file operations like :func:`os.close` they can
(accidentally or maliciously) affect each other's open files. Because of the (accidentally or maliciously) affect each other's open files. Because of the
way extensions are shared between (sub-)interpreters, some extensions may not way extensions are shared between (sub-)interpreters, some extensions may not
work properly; this is especially likely when the extension makes use of work properly; this is especially likely when using single-phase initialization
(static) global variables, or when the extension manipulates its module's or (static) global variables.
dictionary after its initialization. It is possible to insert objects created It is possible to insert objects created in one sub-interpreter into
in one sub-interpreter into a namespace of another sub-interpreter; this should a namespace of another (sub-)interpreter; this should be avoided if possible.
be done with great care to avoid sharing user-defined functions, methods,
instances or classes between sub-interpreters, since import operations executed Special care should be taken to avoid sharing user-defined functions,
by such objects may affect the wrong (sub-)interpreter's dictionary of loaded methods, instances or classes between sub-interpreters, since import
modules. operations executed by such objects may affect the wrong (sub-)interpreter's
dictionary of loaded modules. It is equally important to avoid sharing
objects from which the above are reachable.
Also note that combining this functionality with :c:func:`PyGILState_\*` APIs Also note that combining this functionality with :c:func:`PyGILState_\*` APIs
is delicate, because these APIs assume a bijection between Python thread states is delicate, because these APIs assume a bijection between Python thread states