拡張モジュールの定義

A C extension for CPython is a shared library (for example, a .so file on Linux, .pyd DLL on Windows), which is loadable into the Python process (for example, it is compiled with compatible compiler settings), and which exports an initialization function.

デフォルトで (つまり、 importlib.machinery.ExtensionFileLoader によって) インポート可能であるためには、共有ライブラリは sys.path 上で利用可能である必要があり、モジュール名と importlib.machinery.EXTENSION_SUFFIXES. に含まれる拡張子で命名する必要があります。

注釈

拡張モジュールのビルド、パッケージ化および配布には、サードパーティのツールが最適であり、このドキュメントの範囲外です。適切なツールの一つは Setuptools であり、ドキュメントは https://setuptools.pypa.io/en/latest/setuptools.html にあります。

Normally, the initialization function returns a module definition initialized using PyModuleDef_Init(). This allows splitting the creation process into several phases:

  • Before any substantial code is executed, Python can determine which capabilities the module supports, and it can adjust the environment or refuse loading an incompatible extension.

  • By default, Python itself creates the module object -- that is, it does the equivalent of object.__new__() for classes. It also sets initial attributes like __package__ and __loader__.

  • Afterwards, the module object is initialized using extension-specific code -- the equivalent of __init__() on classes.

This is called multi-phase initialization to distinguish it from the legacy (but still supported) single-phase initialization scheme, where the initialization function returns a fully constructed module. See the single-phase-initialization section below for details.

バージョン 3.5 で変更: 多段階初期化 (PEP 489) のサポートを追加しました。

複数のモジュールインスタンス

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.

サブインタープリタ 内や、Python ランタイムの再初期化 (Py_Finalize() と Py_Initialize()) 後にも、追加のモジュールインスタンスが作成される可能性があります。 これらの場合、モジュールインスタンス間で Python オブジェクトを共有すると、クラッシュや未定義の動作を引き起こしやすくなります。

このような問題を避けるには、拡張モジュールの各インスタンスを 分離 する必要があります。 あるインスタンスの変更が暗黙に他のインスタンスに影響してはいけません。 また、Python オブジェクトへの参照を含む、モジュールが所有するすべての状態は、特定のモジュールインスタンスだけのものでなければなりません。 詳細と実践的な手引きは 拡張モジュールを分離する を参照してください。

これらの問題を避けるより簡単な方法は、初期化を繰り返すとエラーを送出する ことです。

すべてのモジュールは サブインタープリタ に対応するか、対応していないことを明示的に通知することが期待されます。 通常は、上述したように分離を行うか、初期化の繰り返しを禁止します。 Py_mod_multiple_interpreters スロットで、モジュールをメインインタープリタに限定することもできます。

Initialization function

The initialization function defined by an extension module has the following signature:

PyObject *PyInit_modulename(void)

Its name should be PyInit_<name>, with <name> replaced by the name of the module.

For modules with ASCII-only names, the function must instead be named PyInit_<name>, with <name> replaced by the name of the module. When using 多段階初期化, non-ASCII module names are allowed. In this case, the initialization function name is PyInitU_<name>, with <name> encoded using Python's punycode encoding with hyphens replaced by underscores. In Python:

def initfunc_name(name):
    try:
        suffix = b'_' + name.encode('ascii')
    except UnicodeEncodeError:
        suffix = b'U_' + name.encode('punycode').replace(b'-', b'_')
    return b'PyInit' + suffix

It is recommended to define the initialization function using a helper macro:

PyMODINIT_FUNC

拡張モジュールの初期化関数を宣言します。 このマクロは次の処理を行います:

  • 戻り値の型として PyObject* を指定します。

  • プラットフォームが要求する特別なリンケージ宣言を追加します。

  • C++ では、関数を extern "C" として宣言します。

例えば spam というモジュールは、次のように定義します。

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

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

It is possible to export multiple modules from a single shared library by defining multiple initialization functions. However, importing them requires using symbolic links or a custom importer, because by default only the function corresponding to the filename is found. See the Multiple modules in one library section in PEP 489 for details.

The initialization function is typically the only non-static item defined in the module's C source.

多段階初期化

Normally, the initialization function (PyInit_modulename) returns a PyModuleDef instance with non-NULL m_slots. Before it is returned, the PyModuleDef instance must be initialized using the following function:

PyObject *PyModuleDef_Init(PyModuleDef *def)
次に属します: Stable ABI (バージョン 3.5 より).

モジュール定義を、自身の型と参照カウントを正しく示す、適切に初期化された Python オブジェクトにします。

def を PyObject* にキャストして返します。 エラーが発生した場合は NULL を返します。

Calling this function is required for 多段階初期化. It should not be used in other contexts.

Python は PyModuleDef 構造体が静的に割り当てられていると仮定することに注意してください。 この関数は新しい参照または借用参照を返しますが、その参照を解放してはいけません。

Added in version 3.5.

従来の一段階初期化

注意

一段階初期化は拡張モジュールを初期化する従来の仕組みであり、既知の欠点や設計上の問題があります。 拡張モジュールの作者には、代わりに多段階初期化を使うことを推奨します。

In single-phase initialization, the 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 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
    

    厳密な動作は CPython の実装の詳細とみなしてください。

  • PyInit_modulename が spec 引数を受け取らないことに対処するため、インポート機構の状態の一部を保存し、PyInit_modulename の呼び出し中に最初に作成された適切なモジュールに適用します。 具体的には、サブモジュールをインポートするとき、この仕組みがモジュール名の先頭に親パッケージ名を付加します。

    一段階初期化の PyInit_modulename 関数は、他のモジュールオブジェクトが作成される前に、できるだけ早く「自身の」モジュールオブジェクトを作成してください。

  • 非 ASCII のモジュール名 (PyInitU_modulename) はサポートされません。

  • 一段階初期化モジュールは、PyState_FindModule() などのモジュール検索関数をサポートします。