CPythonをC言語で拡張(2): Pythonの型を増やす

前回に引き続き、今回はstr型やlist型のようなCPythonの「型」をC言語で拡張する。

以下を参照してほしい:

概要

基本的に定義するものは以下のようになる:

CPythonの型をC言語で拡張するときのコンポーネント

(ただし、__newなどのアンダーバーは新しい型名などで書く。例えばNewType_newなど。)

左側は前回定義したModuleと同じだ。さらに型を定義するには、図右側のType関連の関数やテーブル:

  1. PyMemberDef: 外側からアクセスできるメンバ変数のテーブル
  2. ライフサイクルの管理用の関数(__dealloc, __new, __init

を追加すれば良い。(詳細は上記チュートリアルを参考にしてほしい。)

コンパイル

setuptoolsにC言語の拡張を扱う機能がある。以下の2つのファイルを書くとpip install -e .だけでC拡張をインストールできるようになる。(これは実は前回にも使える。)

以下は上記チュートリアルのすべてのファイルをコンパイルする場合の処理: setup.py:

from setuptools import Extension, setup
setup(ext_modules=[
  Extension("custom", ["custom.c"]),    # Pure type
  Extension("custom2", ["custom2.c"]),  # Type + its operators
  Extension("custom3", ["custom3.c"]),  # Adding finer control of class variables
  Extension("custom4", ["custom4.c"]),  # GC
  Extension("sublist", ["custom5.c"])   # Inheritence of List
])

pyproject.toml:

[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[project]
name = "custom"
version = "1"

Gabage Collection (GC)

ライフサイクルは循環参照も考慮した Cyclic Gabage Collection を使うこともできる。そのために必要なのは以下の3つを追加、書き換えが必要になる。

static int __traverse(CustomObject *self, visitproc visit, void *arg);
static int __clear(CustomObject *self)
static PyObject *Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)

基本的には依存関係をtraverseに伝えるだけにする、ルーチン的な処理ですむ。後でIRのグラフの探索ができるようにするようだ。