前回に引き続き、今回はstr
型やlist
型のようなCPythonの「型」をC言語で拡張する。
以下を参照してほしい:
- 2. Defining Extension Types: Tutorial — Python 3.12.5 documentation
- 2. 拡張の型の定義: チュートリアル — Python 3.12.5 ドキュメント
概要
基本的に定義するものは以下のようになる:
(ただし、__new
などのアンダーバーは新しい型名などで書く。例えばNewType_new
など。)
左側は前回定義したModule
と同じだ。さらに型を定義するには、図右側のType
関連の関数やテーブル:
PyMemberDef
: 外側からアクセスできるメンバ変数のテーブル- ライフサイクルの管理用の関数(
__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のグラフの探索ができるようにするようだ。