Definiowanie modułów rozszerzeń¶
Rozszerzeniem języka C dla CPython jest współdzielona biblioteka (na .so przykład plik w systemie Linux, .pyd biblioteka DLL w systemie Windows), którą można załadować do proces Pythona (na przykład skompilować z użyciem zgodnych ustawień kompilatora) i która eksportuje funkcja export hook (lub staromodną funkcja inicjalizacja :ref:` <extension-pyinit>).
Aby można było importować współdzielona biblioteka współdzieloną domyślny (czyli przez importlib.machinery.ExtensionFileLoader ), musi być ona dostępna w sys.path, a jej nazwa musi składać się z nazwy moduł i rozszerzenia wymienionego w:py:attr:importlib.machinery.EXTENSION_SUFFIXES .
Informacja
Kompilację, pakowanie i dystrybucję modułów rozszerzeń zewnętrzny wykonywać za pomocą narzędzi firm trzecich, co wykracza poza zakres niniejszego dokumentu. Jednym z odpowiednich narzędzi jest Setuptools, którego dokumentację można znaleźć pod adresem https://setuptools.pypa.io/en/latest/setuptools.html.
Hak eksportowy przedłużacza¶
Dodane w wersji 3.15: wparcie Obsługa haka PyModExport_<name> eksportu została dodana w Python 3.15. Starszy sposób definiowania moduł jest nadal dostępny: zapoznaj się z PyInit function sekcją lub wcześniejszymi wersja tej dokumentacji, jeśli planujesz wparcie wparcie wersja Pythona.
Hak eksportowy musi być eksportowaną funkcja o następującym podpisie:
W przypadku modułów z nazwami zawierającymi wyłącznie znaki ASCII, parametr export hook musi mieć nazwę PyModExport_<name>, a ``<name>``następnie zostać zastąpiony nazwą modułu.
W przypadku nazw modułów spoza zestawu ASCII hak eksportu musi zostać nazwany PyModExportU_<name>`(zwróć uwagę na ``U` ), <name> zakodowany przy użyciu kodowania punycode języka Python, z myślnikami zastąpionymi podkreśleniami. W Python:
def hook_name(name):
try:
przyrostek = b'_' + name.encode('ascii')
except UnicodeEncodeError:
przyrostek = b'U_' + name.encode('punycode').replace(b'-', b'_')
zwracać b'PyModExport' + przyrostek
Hak eksportu zwracać tablica PySlot wpisów zakończoną wpisem o identyfikatorze slotu równym 0. Sloty te opisują sposób tworzenia i inicjalizacji moduł.
Ta tablica musi ważny prawidłowa i stała do momentu zamknięcia static interpreter . Zazwyczaj powinna korzystać Py_mod_create`z :c:macro:`Py_mod_exec pamięci masowej. Preferowane jest używanie slotów i w przypadku wszelkich dynamicznych zachowanie.
Hak eksportu może zwracać NULL wyjątek ustawiony na sygnał awarii.
Zaleca się zdefiniowanie funkcja haka eksportu za pomocą makro pomocniczego:
-
PyMODEXPORT_FUNC¶
- Część stabilnego ABI od wersji 3.15.
Zadeklaruj hak eksportu moduł rozszerzenia. To makro:
określa PySlot* typ zwracać,
dodaje wszelkie specjalne deklaracje połączeń wymagane przez platformę i
dla C++ deklaruje funkcja jako
Na przykład moduł o spam nazwie zostałby zdefiniowany w następujący sposób:
PyABIInfo_VAR(abi_info);
static PySlot spam_slots[] = {
PySlot_STATIC_DATA(Py_mod_abi, &abi_info),
PySlot_STATIC_DATA(Py_mod_name, "spam"),
PySlot_FUNC(Py_mod_init, spam_init_function),
...
PySlot_END
};
PyMODEXPORT_FUNC
PyModExport_spam(void)
{
zwracać spam_slots;
}
Hak eksportu jest zazwyczaj jedynym elementem innym niż static zdefiniowanym w kodzie źródłowym moduł C.
Hak powinien być krótki – najlepiej jeden wiersz, jak powyżej. Jeśli jednak musisz użyć API Python C API w tej funkcja, zaleca się najpierw wywołać ją, aby zgłosić rzucić wyjątek, zamiast spowodować awarię, w typowych przypadkach niezgodności ABI.
Informacja
Możliwe jest eksportowanie wielu moduł z jednej biblioteki współdzielona biblioteka poprzez zdefiniowanie wielu haków eksportu. Ich importowanie wymaga jednak użycia niestandardowego importera lub odpowiednio nazwanych kopii/linków pliku rozszerzenia, ponieważ mechanizm importu Pythona znajduje tylko funkcja odpowiadającą nazwie pliku. Szczegółowe informacje moduł można znaleźć w sekcji „Wiele modułów w jednej biblioteka”. <https://peps.python.org/pep-0489/#multiple-modules-in-one-library>`__ section in PEP 489 for details.
Inicjalizacja wielofazowa¶
przetwarzanie/proces przetwarzanie tworzenia moduł rozszerzenia przebiega w kilku fazach:
Python wyszukuje i wywołuje hak eksportu, aby uzyskać informacje o sposobie tworzenia moduł.
Zanim zostanie wykonany jakikolwiek istotny kod, Python może określić, jakie możliwości obsługuje moduł, i dostosować środowisko lub odmówić załadowania niekompatybilnego rozszerzenia. Na ten krok wpływają sloty takie jak
Py_mod_abi,Py_mod_gil`i :c:data:`Py_mod_multiple_interpreters.domyślny Python sam tworzy obiekt moduł – czyli wykonuje czynność odpowiadającą wywołaniu
__new__()podczas tworzenia obiektu. Ten krok można pominąć za pomocąPy_mod_createslotu.Python ustawia początkowe atrybuty moduł, takie jak
__package__i__loader__, i wstawia obiekt modułu dosys.modules.Afterwards, the module object is initialized in an extension-specific way – the equivalent of
__init__()when creating an object, or of executing top-level code in a Python-language module. The behavior is specified using thePy_mod_execslot.
This is called multi-phase initialization to distinguish it from the legacy (but still supported) single-phase initialization, where an initialization function returns a fully constructed module.
Zmienione w wersji 3.5: Added support for multi-phase initialization (PEP 489).
Multiple module instances¶
By default, extension modules are not singletons.
For example, if the sys.modules entry is removed and the module
is re-imported, a new module object is created and, typically, populated with
fresh method and type objects.
The old module is subject to normal garbage collection.
This mirrors the behavior of pure-Python modules.
Additional module instances may be created in
sub-interpreters
or after Python runtime reinitialization
(Py_Finalize() and Py_Initialize()).
In these cases, sharing Python objects between module instances would likely
cause crashes or undefined behavior.
To avoid such issues, each instance of an extension module should be isolated: changes to one instance should not implicitly affect the others, and all state owned by the module, including references to Python objects, should be specific to a particular module instance. See Isolating Extension Modules for more details and a practical guide.
A simpler way to avoid these issues is raising an error on repeated initialization.
All modules are expected to support
sub-interpreters, or otherwise explicitly
signal a lack of support.
This is usually achieved by isolation or blocking repeated initialization,
as above.
A module may also be limited to the main interpreter using
the Py_mod_multiple_interpreters slot.
PyInit function¶
Soft deprecated since version 3.15: This functionality will not get new features, but there are no plans to remove it.
Instead of PyModExport_modulename(), an extension module can define
an older-style initialization function with the signature:
Its name should be PyInit_<name>, with <name> replaced by the
name of the module.
For non-ASCII module names, use PyInitU_<name> instead, with
<name> encoded in the same way as for the
export hook (that is, using Punycode
with underscores).
If a module exports both PyInit_<name> and
PyModExport_<name>, the PyInit_<name> function
is ignored.
Like with PyMODEXPORT_FUNC, it is recommended to define the
initialization function using a helper macro:
-
PyMODINIT_FUNC¶
Declare an extension module initialization function. This macro:
specifies the PyObject* return type,
dodaje wszelkie specjalne deklaracje połączeń wymagane przez platformę i
dla C++ deklaruje funkcja jako
Normally, the initialization function (PyInit_modulename) returns
a PyModuleDef instance with non-NULL
m_slots. This allows Python to use
multi-phase initialization.
Before it is returned, the PyModuleDef instance must be initialized
using the following function:
-
PyObject *PyModuleDef_Init(PyModuleDef *def)¶
- Część stabilnego ABI od wersji 3.5.
Ensure a module definition is a properly initialized Python object that correctly reports its type and a reference count.
Return def cast to
PyObject*, orNULLif an error occurred.Calling this function is required before returning a
PyModuleDeffrom a module initialization function. It should not be used in other contexts.Note that Python assumes that
PyModuleDefstructures are statically allocated. This function may return either a new reference or a borrowed one; this reference must not be released.Dodane w wersji 3.5.
Na przykład moduł o spam nazwie zostałby zdefiniowany w następujący sposób:
static struct PyModuleDef spam_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "spam",
...
};
PyMODINIT_FUNC
PyInit_spam(void)
{
return PyModuleDef_Init(&spam_module);
}
Legacy single-phase initialization¶
Soft deprecated since version 3.15: Single-phase initialization is a legacy mechanism to initialize extension modules, with known drawbacks and design flaws. Extension module authors are encouraged to use multi-phase initialization instead.
However, there are no plans to remove support for it.
In single-phase initialization, the old-style
initialization function (PyInit_modulename)
should create, populate and return a module object.
This is typically done using PyModule_Create() and functions like
PyModule_AddObjectRef().
Single-phase initialization differs from the default in the following ways:
Single-phase modules are, or rather contain, “singletons”.
When the module is first initialized, Python saves the contents of the module’s
__dict__(that is, typically, the module’s functions and types).For subsequent imports, Python does not call the initialization function again. Instead, it creates a new module object with a new
__dict__, and copies the saved contents to it. For example, given a single-phase module_testsinglephase[1] that defines a functionsumand an exception classerror:>>> import sys >>> import _testsinglephase as one >>> del sys.modules['_testsinglephase'] >>> import _testsinglephase as two >>> one is two False >>> one.__dict__ is two.__dict__ False >>> one.sum is two.sum True >>> one.error is two.error True
The exact behavior should be considered a CPython implementation detail.
To work around the fact that
PyInit_modulenamedoes not take a spec argument, some state of the import machinery is saved and applied to the first suitable module created during thePyInit_modulenamecall. Specifically, when a sub-module is imported, this mechanism prepends the parent package name to the name of the module.A single-phase
PyInit_modulenamefunction should create “its” module object as soon as possible, before any other module objects can be created.Non-ASCII module names (
PyInitU_modulename) are not supported.Single-phase modules support module lookup functions like
PyState_FindModule().The module’s
PyModuleDef.m_slotsmust be NULL.