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:

PySlot *PyModExport_modulename(void)

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_create slotu.

  • Python ustawia początkowe atrybuty moduł, takie jak __package__ i __loader__, i wstawia obiekt modułu do sys.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 the Py_mod_exec slot.

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:

PyObject *PyInit_modulename(void)

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*, or NULL if an error occurred.

Calling this function is required before returning a PyModuleDef from a module initialization function. It should not be used in other contexts.

Note that Python assumes that PyModuleDef structures 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 function sum and an exception class error:

    >>> 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_modulename does not take a spec argument, some state of the import machinery is saved and applied to the first suitable module created during the PyInit_modulename call. Specifically, when a sub-module is imported, this mechanism prepends the parent package name to the name of the module.

    A single-phase PyInit_modulename function 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_slots must be NULL.