拡張の型の定義: チュートリアル
******************************

Python では、組み込みの "str" 型や "list" 型のような Python コードから
操作できる新しい型を C 拡張モジュールの作者が定義できます。 全ての拡張
の型のコードはあるパターンに従うのですが、書き始める前に理解しておくべ
き細かいことがあります。 このドキュメントはその話題についてのやさしい
入門です。


基本的なこと
============

*CPython* ランタイムは、すべての Python オブジェクトを PyObject* 型の
変数として扱います。 この型はすべての Python オブジェクトの「基底型」
の役割を果たします。 "PyObject" 構造体自体に含まれるのは、オブジェクト
の *参照カウント* と、その「型オブジェクト」へのポインタだけです。 動
作を決めるのは、この型オブジェクトです。 例えばオブジェクトの属性を検
索するとき、メソッドを呼び出すとき、ほかのオブジェクトとの乗算を行うと
きに、インタープリタがどの C 関数を呼び出すかを決定します。 これらの C
関数を「型メソッド」と呼びます。

それなので、新しい拡張の型を定義したいときは、新しい型オブジェクトを作
成すればよいわけです。

この手のことは例を見たほうが早いでしょうから、以下に C 拡張モジュール
"custom" にある "Custom" という名前の新しい型を定義する、最小限ながら
完全なモジュールをあげておきます:

注釈:

  ここで紹介している例は、 *静的な* 拡張の型を定義する伝統的な実装方法
  です。 これはほとんどの場面で十分なものなのです。 C API では、
  "PyType_FromSpec()" 関数を使い、ヒープ上に配置された拡張の型も定義で
  きますが、これについてはこのチュートリアルでは扱いません。

   #define PY_SSIZE_T_CLEAN
   #include <Python.h>

   typedef struct {
       PyObject_HEAD
       /* 型固有のフィールドをここに記述します。 */
   } CustomObject;

   static PyTypeObject CustomType = {
       .ob_base = PyVarObject_HEAD_INIT(NULL, 0)
       .tp_name = "custom.Custom",
       .tp_doc = PyDoc_STR("Custom オブジェクト"),
       .tp_basicsize = sizeof(CustomObject),
       .tp_itemsize = 0,
       .tp_flags = Py_TPFLAGS_DEFAULT,
       .tp_new = PyType_GenericNew,
   };

   static int
   custom_module_exec(PyObject *m)
   {
       if (PyType_Ready(&CustomType) < 0) {
           return -1;
       }

       if (PyModule_AddObjectRef(m, "Custom", (PyObject *) &CustomType) < 0) {
           return -1;
       }

       return 0;
   }

   static PyModuleDef_Slot custom_module_slots[] = {
       {Py_mod_exec, custom_module_exec},
       // 静的な型を使う間はこの設定を使う
       {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},
       {0, NULL}
   };

   static PyModuleDef custom_module = {
       .m_base = PyModuleDef_HEAD_INIT,
       .m_name = "custom",
       .m_doc = "拡張型を作成するサンプルモジュール。",
       .m_size = 0,
       .m_slots = custom_module_slots,
   };

   PyMODINIT_FUNC
   PyInit_custom(void)
   {
       return PyModuleDef_Init(&custom_module);
   }

一度に理解するにはかなりの量ですが、前の章で見たことのある部分もあるで
しょう。 このファイルでは、次の三つを定義しています。

1. "Custom" **オブジェクト** が何を含んでいるか: これが "CustomObject"
   構造体で、 "Custom" インスタンスごとに1回だけメモリ確保が行われます
   。

2. "Custom" **型** がどのように振る舞うか: これが "CustomType" 構造体
   で、フラグと関数ポインタの集まりを定義しています。特定の操作が要求
   されたときに、この関数ポインタをインタープリターが見に行きます。

3. "custom" モジュールをどう定義し、実行するか。 モジュールを定義する
   "PyInit_custom" 関数と、それに関連する "custom_module" 構造体、およ
   び新しいモジュールオブジェクトを設定する "custom_module_exec" 関数
   がこれに当たります。

まず最初はこれです:

   typedef struct {
       PyObject_HEAD
   } CustomObject;

これが Custom オブジェクトの内容です。 各オブジェクト構造体の先頭には
"PyObject_HEAD" が必須で、これは "PyObject" 型の "ob_base" というフィ
ールドを定義します。 このフィールドには型オブジェクトへのポインタと参
照カウントが含まれ、それぞれ "Py_TYPE" と "Py_REFCNT" マクロでアクセス
できます。 このマクロはレイアウトを抽象化し、デバッグビルド でフィール
ドを追加できるようにするためのものです。

注釈:

  上の例では "PyObject_HEAD" マクロの後にセミコロンはありません。 うっ
  かりセミコロンを追加しないように気を付けてください: これを警告するコ
  ンパイラもあります。

もちろん、一般的にはオブジェクトは標準的な "PyObject_HEAD" ボイラープ
レートの他にもデータを保持しています; 例えば、これは Python 標準の浮動
小数点数の定義です:

   typedef struct {
       PyObject_HEAD
       double ob_fval;
   } PyFloatObject;

2つ目は型オブジェクトの定義です。

   static PyTypeObject CustomType = {
       .ob_base = PyVarObject_HEAD_INIT(NULL, 0)
       .tp_name = "custom.Custom",
       .tp_doc = PyDoc_STR("Custom オブジェクト"),
       .tp_basicsize = sizeof(CustomObject),
       .tp_itemsize = 0,
       .tp_flags = Py_TPFLAGS_DEFAULT,
       .tp_new = PyType_GenericNew,
   };

注釈:

  上にあるように C99 スタイルの指示付き初期化子を使って、
  "PyTypeObject" の特に関心の無いフィールドまで全て並べたり、フィール
  ドを宣言する順序に気を使ったりせずに済ませるのをお薦めします。

"object.h" にある実際の "PyTypeObject" の定義には上の定義にあるよりも
もっと多くの フィールド があります。 ここに出てきていないフィールドは
C コンパイラによってゼロで埋められるので、必要でない限り明示的には値の
指定をしないのが一般的な作法になっています。

一度に1つずつフィールドを取り上げていきましょう:

   .ob_base = PyVarObject_HEAD_INIT(NULL, 0)

この行は、上で説明した "ob_base" フィールドを初期化するために必要な定
型的な記述です。

   .tp_name = "custom.Custom",

実装している型の名前です。 これは、オブジェクトのデフォルトの文字列表
現やエラーメッセージに現れます。例えば次の通りです:

   >>> "" + custom.Custom()
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   TypeError: can only concatenate str (not "custom.Custom") to str

型の名前は、モジュール名とモジュール内の型の名前をドットでつないだ名前
です。 この場合、モジュールは "custom"、型は "Custom" なので、型の名前
を "custom.Custom" に設定します。 この型を "pydoc" や "pickle" モジュ
ールと互換性のあるものにするには、実際のドット付きインポートパスを使う
ことが重要です。

   .tp_basicsize = sizeof(CustomObject),
   .tp_itemsize = 0,

これは、新しい "Custom" インスタンスを作るときに Python が割り当てるべ
きメモリがどのくらいなのかを知るためのものです。 "tp_itemsize" は可変
サイズのオブジェクトでのみ使うものなので、サイズが可変でないオブジェク
トでは 0 にすべきです。

注釈:

  Python からサブクラスを作成できる型で、その "tp_basicsize" が基底型
  と同じ場合は、多重継承で問題が起こる可能性があります。 その型の
  Python サブクラスでは、"__bases__" の先頭にその型を指定しないと、そ
  の型の "__new__()" メソッドを呼び出す際にエラーが発生します。 この問
  題は、型の "tp_basicsize" を基底型より大きな値にすることで避けられま
  す。 たいていの場合、基底型が "object" であるか、基底型にデータメン
  バを追加してサイズを増やすので、すでにこの条件を満たしています。

"Py_TPFLAGS_DEFAULT" にクラスフラグを設定します。

   .tp_flags = Py_TPFLAGS_DEFAULT,

すべての型はフラグにこの定数を含めておく必要があります。これは最低でも
Python 3.3 までに定義されているすべてのメンバを許可します。それ以上の
メンバが必要なら、対応するフラグの OR をとる必要があります。

この型の docstring は "tp_doc" に入れます。

   .tp_doc = PyDoc_STR("Custom オブジェクト"),

オブジェクトが生成できるように、 "tp_new" ハンドラを提供する必要があり
ます。これは Python のメソッド "__new__()" と同等のものですが、明示的
に与える必要があります。今の場合では、 API 関数の
"PyType_GenericNew()" として提供されるデフォルトの実装をそのまま使えま
す。

   .tp_new = PyType_GenericNew,

ファイル内の残りの部分は、"custom_module_exec()" の一部を除いて、すで
に見慣れたものでしょう。

   if (PyType_Ready(&CustomType) < 0) {
       return -1;
   }

これは、 "NULL" に初期化された "ob_type" も含めて、いくつかのメンバー
を適切なデフォルト値で埋めて、 "Custom" 型を初期化します。

   if (PyModule_AddObjectRef(m, "Custom", (PyObject *) &CustomType) < 0) {
       return -1;
   }

これは型をモジュールの辞書に追加します。こうすることで "Custom" クラス
の呼び出しで "Custom" インスタンスが作成できるようになります:

   >>> import custom
   >>> mycustom = custom.Custom()

以上です!残りの作業はビルドだけです; "custom.c" という名前のファイルに
ここまでのコードを書き込み、

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

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

"pyproject.toml" というファイルにこれを書き込み、

   from setuptools import Extension, setup
   setup(ext_modules=[Extension("custom", ["custom.c"])])

そして "setup.py" というファイルにこのように書き込み、そして、以下のよ
うに

   $ python -m pip install .

シェルに入力します。これにより、サブディレクトリに "custom.so" が生成
され、インストールされます。これで、 Python を立ち上げて、 "import
custom" すると "Custom" オブジェクトで遊べるようになっているはずです。

そんなにむずかしくありません、よね?

もちろん、現在の Custom 型は面白みに欠けています。何もデータを持ってい
ないし、何もできません。継承してサブクラスを作ることさえできないのです
。


基本のサンプルにデータとメソッドを追加する
==========================================

この基本のサンプルにデータとメソッドを追加してみましょう。ついでに、こ
の型を基底クラスとしても利用できるようにします。ここでは新しいモジュー
ル "custom2" をつくり、これらの機能を追加します:

   #define PY_SSIZE_T_CLEAN
   #include <Python.h>
   #include <stddef.h> /* offsetof() 用 */

   typedef struct {
       PyObject_HEAD
       PyObject *first; /* ファーストネーム */
       PyObject *last;  /* ラストネーム */
       int number;
   } CustomObject;

   static void
   Custom_dealloc(PyObject *op)
   {
       CustomObject *self = (CustomObject *) op;
       Py_XDECREF(self->first);
       Py_XDECREF(self->last);
       Py_TYPE(self)->tp_free(self);
   }

   static PyObject *
   Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   {
       CustomObject *self;
       self = (CustomObject *) type->tp_alloc(type, 0);
       if (self != NULL) {
           self->first = Py_GetConstant(Py_CONSTANT_EMPTY_STR);
           if (self->first == NULL) {
               Py_DECREF(self);
               return NULL;
           }
           self->last = Py_GetConstant(Py_CONSTANT_EMPTY_STR);
           if (self->last == NULL) {
               Py_DECREF(self);
               return NULL;
           }
           self->number = 0;
       }
       return (PyObject *) self;
   }

   static int
   Custom_init(PyObject *op, PyObject *args, PyObject *kwds)
   {
       CustomObject *self = (CustomObject *) op;
       static char *kwlist[] = {"first", "last", "number", NULL};
       PyObject *first = NULL, *last = NULL;

       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
                                        &first, &last,
                                        &self->number))
           return -1;

       if (first) {
           Py_XSETREF(self->first, Py_NewRef(first));
       }
       if (last) {
           Py_XSETREF(self->last, Py_NewRef(last));
       }
       return 0;
   }

   static PyMemberDef Custom_members[] = {
       {"first", Py_T_OBJECT_EX, offsetof(CustomObject, first), 0,
        "ファーストネーム"},
       {"last", Py_T_OBJECT_EX, offsetof(CustomObject, last), 0,
        "ラストネーム"},
       {"number", Py_T_INT, offsetof(CustomObject, number), 0,
        "独自の数値"},
       {NULL}  /* 番兵 */
   };

   static PyObject *
   Custom_name(PyObject *op, PyObject *Py_UNUSED(dummy))
   {
       CustomObject *self = (CustomObject *) op;
       if (self->first == NULL) {
           PyErr_SetString(PyExc_AttributeError, "first");
           return NULL;
       }
       if (self->last == NULL) {
           PyErr_SetString(PyExc_AttributeError, "last");
           return NULL;
       }
       return PyUnicode_FromFormat("%S %S", self->first, self->last);
   }

   static PyMethodDef Custom_methods[] = {
       {"name", Custom_name, METH_NOARGS,
        "ファーストネームとラストネームを連結した名前を返す"
       },
       {NULL}  /* 番兵 */
   };

   static PyTypeObject CustomType = {
       .ob_base = PyVarObject_HEAD_INIT(NULL, 0)
       .tp_name = "custom2.Custom",
       .tp_doc = PyDoc_STR("Custom オブジェクト"),
       .tp_basicsize = sizeof(CustomObject),
       .tp_itemsize = 0,
       .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
       .tp_new = Custom_new,
       .tp_init = Custom_init,
       .tp_dealloc = Custom_dealloc,
       .tp_members = Custom_members,
       .tp_methods = Custom_methods,
   };

   static int
   custom_module_exec(PyObject *m)
   {
       if (PyType_Ready(&CustomType) < 0) {
           return -1;
       }

       if (PyModule_AddObjectRef(m, "Custom", (PyObject *) &CustomType) < 0) {
           return -1;
       }

       return 0;
   }

   static PyModuleDef_Slot custom_module_slots[] = {
       {Py_mod_exec, custom_module_exec},
       {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},
       {0, NULL}
   };

   static PyModuleDef custom_module = {
       .m_base = PyModuleDef_HEAD_INIT,
       .m_name = "custom2",
       .m_doc = "拡張型を作成するサンプルモジュール。",
       .m_size = 0,
       .m_slots = custom_module_slots,
   };

   PyMODINIT_FUNC
   PyInit_custom2(void)
   {
       return PyModuleDef_Init(&custom_module);
   }

モジュールのこのバージョンでは、いくつもの変更をおこないます。

"Custom" 型は そのC構造体に 3つのデータ属性 *first* 、 *last* 、および
*number* をもつようになりました。 *first* と *last* 属性はファーストネ
ームとラストネームを格納した Python 文字列で、 *number* 属性は C言語で
の整数の値です。

これにしたがうと、オブジェクトの構造体は次のようになります:

   typedef struct {
       PyObject_HEAD
       PyObject *first; /* ファーストネーム */
       PyObject *last;  /* ラストネーム */
       int number;
   } CustomObject;

いまや管理すべきデータができたので、オブジェクトの割り当てと解放に際し
てはより慎重になる必要があります。最低限、オブジェクトの解放メソッドが
必要です:

   static void
   Custom_dealloc(PyObject *op)
   {
       CustomObject *self = (CustomObject *) op;
       Py_XDECREF(self->first);
       Py_XDECREF(self->last);
       Py_TYPE(self)->tp_free(self);
   }

この関数は "tp_dealloc" メンバに代入されます。

   .tp_dealloc = Custom_dealloc,

このメソッドは、まず二つのPython 属性の参照カウントをクリアします。
"Py_XDECREF()" は引数が "NULL" のケースを正しく扱えます (これは、
"tp_new" が途中で失敗した場合に起こりえます) 。このメソッドは、つぎに
オブジェクトの型 ("Py_TYPE(self)" で算出します) のメンバ "tp_free" を
呼び出し、オブジェクトのメモリを開放します。オブジェクトの型が
"CustomType" であるとは限らない点に注意してください。なぜなら、オブジ
ェクトはサブクラスのインスタンスかもしれないからです。

注釈:

  "tp_dealloc" 関数ポインタが "PyObject *" 引数を受け取るため、
  "Custom_dealloc" も "PyObject *" 引数を受け取るように定義しています
  。 そのため、上の例では "CustomObject *" への明示的なキャストが必要
  です。 この関数を型の "tp_dealloc" スロットに代入することで、
  "CustomObject" クラスのインスタンスに対してだけ呼び出されることを宣
  言しているので、"(CustomObject *)" へのキャストは安全です。 これが C
  でのオブジェクト指向のポリモーフィズムです。既存のコードやこのチュー
  トリアルの以前のバージョンでは、次のようにサブタイプのオブジェクト構
  造体へのポインタ ("CustomObject*") を直接受け取る関数を見かけるかも
  しれません。

     Custom_dealloc(CustomObject *self)
     {
         Py_XDECREF(self->first);
         Py_XDECREF(self->last);
         Py_TYPE(self)->tp_free((PyObject *) self);
     }
     ...
     .tp_dealloc = (destructor) Custom_dealloc,

  CPython がサポートするすべてのアーキテクチャでは同じ動作になりますが
  、C の規格上は未定義の動作を引き起こします。

ファーストネームとラストネームを空文字列に初期化しておきたいので、
"tp_new" の実装を追加することにしましょう:

   static PyObject *
   Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   {
       CustomObject *self;
       self = (CustomObject *) type->tp_alloc(type, 0);
       if (self != NULL) {
           self->first = PyUnicode_FromString("");
           if (self->first == NULL) {
               Py_DECREF(self);
               return NULL;
           }
           self->last = PyUnicode_FromString("");
           if (self->last == NULL) {
               Py_DECREF(self);
               return NULL;
           }
           self->number = 0;
       }
       return (PyObject *) self;
   }

そしてこれを "tp_new" メンバとしてインストールします:

   .tp_new = Custom_new,

"tp_new" ハンドラは、その型のオブジェクトの初期化ではなく、作成を担当
します。 Python では "__new__()" メソッドとして公開されます。 "tp_new"
メンバを独自に定義する必要はなく、実際、多くの拡張型は、上の最初の
"Custom" 型と同じく "PyType_GenericNew()" をそのまま使います。 今回は
"tp_new" ハンドラを使って、"first" と "last" 属性を "NULL" でないデフ
ォルト値に初期化します。

"tp_new" にはインスタンス化する型 (サブクラスをインスタンス化する場合
は必ずしも "CustomType" とは限りません) と、その型の呼び出し時に渡され
た引数を渡します。 作成したインスタンスを返す必要があります。 "tp_new"
ハンドラは常に位置引数とキーワード引数を受け取りますが、それらを無視し
て、初期化メソッド (C では "tp_init"、Python では "__init__") に引数の
処理を任せることもよくあります。

注釈:

  "tp_new" は明示的に "tp_init" を呼び出してはいけません、これはインタ
  ープリタが自分で行うためです。

この "tp_new" の実装は、"tp_alloc" スロットを呼び出してメモリを割り当
てます:

   self = (CustomObject *) type->tp_alloc(type, 0);

メモリ割り当ては失敗するかもしれないので、先に進む前に "tp_alloc" の結
果が "NULL" でないかチェックしなければなりません。

注釈:

  ここでは "tp_alloc" スロットを自分では設定していません。
  "PyType_Ready()" が、デフォルトでは "object" となる基底クラスから継
  承して設定してくれます。 ほとんどの型は、デフォルトの割り当て方法を
  使います。

注釈:

  基底型の "tp_new" や "__new__()" を呼び出す、協調的な "tp_new" を実
  装する場合、実行時のメソッド解決順序を使って呼び出すメソッドを決めよ
  うとしては *いけません*。 呼び出す型を常に静的に決め、その "tp_new"
  を直接、または "type->tp_base->tp_new" を通して呼び出してください。
  そうしないと、この型の Python サブクラスが、ほかの Python で定義され
  たクラスも継承する場合に正しく動作しない可能性があります。 具体的に
  は、そのようなサブクラスのインスタンスを作ろうとすると "TypeError"
  が発生する場合があります。

インスタンスの初期値を引数として受け取る初期化関数も定義し、

   static int
   Custom_init(PyObject *op, PyObject *args, PyObject *kwds)
   {
       CustomObject *self = (CustomObject *) op;
       static char *kwlist[] = {"first", "last", "number", NULL};
       PyObject *first = NULL, *last = NULL, *tmp;

       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
                                        &first, &last,
                                        &self->number))
           return -1;

       if (first) {
           tmp = self->first;
           Py_INCREF(first);
           self->first = first;
           Py_XDECREF(tmp);
       }
       if (last) {
           tmp = self->last;
           Py_INCREF(last);
           self->last = last;
           Py_XDECREF(tmp);
       }
       return 0;
   }

これは "tp_init" メンバに代入されます。

   .tp_init = Custom_init,

"tp_init" スロットは、Python では "__init__()" メソッドとして公開され
ます。 作成後のオブジェクトを初期化するために使います。 初期化関数は常
に位置引数とキーワード引数を受け取り、成功した場合は "0"、エラーの場合
は "-1" を返す必要があります。

"tp_new" ハンドラと異なり、"tp_init" が呼ばれる保証はありません (例え
ば "pickle" モジュールは、デフォルトでは unpickle したインスタンスに対
して "__init__()" を呼び出しません)。 また、複数回呼ばれることもありま
す。 誰でもこのオブジェクトの "__init__()" メソッドを呼び出せるからで
す。 そのため、新しい属性値を代入するときは特に注意する必要があります
。 例えば、"first" メンバを次のように代入したくなるかもしれません。

   if (first) {
       Py_XDECREF(self->first);
       Py_INCREF(first);
       self->first = first;
   }

しかし、これは危険です。 この型は "first" メンバの型を制限していないの
で、どのようなオブジェクトでも格納できます。 そのオブジェクトのデスト
ラクタが、"first" メンバにアクセスするコードを実行する可能性があります
。 また、デストラクタが *スレッド状態* をデタッチし、別のスレッドで任
意のコードが動いて、このオブジェクトにアクセスしたり変更したりする可能
性もあります。

この可能性にも十分に注意して対処するため、ほとんどの場合は、参照カウン
トを減らす前にメンバに新しい値を代入します。 では、このようにする必要
がないのはどのような場合でしょうか。

* その参照カウントが 1 より大きいと確信できる場合

* オブジェクト [1] の解放で、*スレッド状態* がデタッチされることも、自
  分の型のコードが呼び戻されることもないと分かっている場合。

* 循環ガベージコレクションをサポートしない型の "tp_dealloc" ハンドラ内
  で、参照カウントを減らす場合 [2]。

ここではインスタンス変数を属性として見えるようにしたいのですが、これに
はいくつもの方法があります。もっとも簡単な方法は、メンバの定義を与える
ことです:

   static PyMemberDef Custom_members[] = {
       {"first", Py_T_OBJECT_EX, offsetof(CustomObject, first), 0,
        "ファーストネーム"},
       {"last", Py_T_OBJECT_EX, offsetof(CustomObject, last), 0,
        "ラストネーム"},
       {"number", Py_T_INT, offsetof(CustomObject, number), 0,
        "独自の数値"},
       {NULL}  /* 番兵 */
   };

そして、この定義を "tp_members" スロットに入れましょう:

   .tp_members = Custom_members,

各メンバ定義には、メンバ名、型、オフセット、アクセスフラグ、ドキュメン
ト文字列があります。 詳細は後述の 総称的な属性を管理する 節を参照して
ください。

この方法の欠点は、Python の属性に代入できるオブジェクトの型を制限でき
ないことです。 ファーストネームとラストネームには文字列を想定していま
すが、任意の Python オブジェクトを代入できてしまいます。 さらに、属性
を削除すると、C のポインタが "NULL" になります。 メンバを "NULL" でな
い値に初期化しても、属性が削除されれば "NULL" に設定されます。

ファーストネームとラストネームを連結してオブジェクトの名前を返す、
"Custom.name()" というメソッドを一つ定義します。

   static PyObject *
   Custom_name(PyObject *op, PyObject *Py_UNUSED(dummy))
   {
       CustomObject *self = (CustomObject *) op;
       if (self->first == NULL) {
           PyErr_SetString(PyExc_AttributeError, "first");
           return NULL;
       }
       if (self->last == NULL) {
           PyErr_SetString(PyExc_AttributeError, "last");
           return NULL;
       }
       return PyUnicode_FromFormat("%S %S", self->first, self->last);
   }

このメソッドは、"Custom" (または "Custom" のサブクラス) のインスタンス
を第 1 引数として受け取る C 関数として実装します。 メソッドは常に第 1
引数としてインスタンスを受け取ります。 多くの場合は位置引数やキーワー
ド引数も受け取りますが、ここではどちらも受け取らないため、位置引数のタ
プルやキーワード引数の辞書を受け取る必要はありません。 このメソッドは
、次の Python メソッドに相当します。

   def name(self):
       return "%s %s" % (self.first, self.last)

"first" と "last" メンバが "NULL" である可能性を確認する必要があります
。 これらの属性は削除可能で、削除された場合は "NULL" に設定されるため
です。 これらの属性を削除できないようにし、値を文字列に制限するとよい
でしょう。 次の節でその方法を説明します。

さて、メソッドを定義したので、ここでメソッド定義用の配列を作成する必要
があります:

   static PyMethodDef Custom_methods[] = {
       {"name", Custom_name, METH_NOARGS,
        "ファーストネームとラストネームを連結した名前を返す"
       },
       {NULL}  /* 番兵 */
   };

("self" 以外の引数を受け取らないことを示すために、"METH_NOARGS" フラグ
を使っています。)

そして、それを "tp_methods" スロットに代入します。

   .tp_methods = Custom_methods,

最後に、この型をサブクラスの基底クラスとして使えるようにします。 ここ
まで、作成するオブジェクトや操作対象のオブジェクトの型を決めつけないよ
うに注意してメソッドを書いてきました。 そのため、クラスのフラグ定義に
"Py_TPFLAGS_BASETYPE" を追加するだけで済みます。

   .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,

"PyInit_custom()" を "PyInit_custom2()" に改名し、"PyModuleDef" 構造体
のモジュール名と "PyTypeObject" 構造体の完全なクラス名を更新します。

最後に、新しいモジュールを含めるよう "setup.py" ファイルを更新し、

   from setuptools import Extension, setup
   setup(ext_modules=[
       Extension("custom", ["custom.c"]),
       Extension("custom2", ["custom2.c"]),
   ])

"import custom2" ができるように再インストールします。

   $ python -m pip install .


データ属性をこまかく制御する
============================

この節では、"Custom" の例で "first" と "last" 属性を設定する方法を、よ
り細かく制御します。 前のバージョンのモジュールでは、インスタンス変数
"first" と "last" に文字列以外の値を設定でき、削除することさえできまし
た。 これらの属性が常に文字列を格納するようにしたいと思います。

   #define PY_SSIZE_T_CLEAN
   #include <Python.h>
   #include <stddef.h> /* offsetof() 用 */

   typedef struct {
       PyObject_HEAD
       PyObject *first; /* ファーストネーム */
       PyObject *last;  /* ラストネーム */
       int number;
   } CustomObject;

   static void
   Custom_dealloc(PyObject *op)
   {
       CustomObject *self = (CustomObject *) op;
       Py_XDECREF(self->first);
       Py_XDECREF(self->last);
       Py_TYPE(self)->tp_free(self);
   }

   static PyObject *
   Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   {
       CustomObject *self;
       self = (CustomObject *) type->tp_alloc(type, 0);
       if (self != NULL) {
           self->first = Py_GetConstant(Py_CONSTANT_EMPTY_STR);
           if (self->first == NULL) {
               Py_DECREF(self);
               return NULL;
           }
           self->last = Py_GetConstant(Py_CONSTANT_EMPTY_STR);
           if (self->last == NULL) {
               Py_DECREF(self);
               return NULL;
           }
           self->number = 0;
       }
       return (PyObject *) self;
   }

   static int
   Custom_init(PyObject *op, PyObject *args, PyObject *kwds)
   {
       CustomObject *self = (CustomObject *) op;
       static char *kwlist[] = {"first", "last", "number", NULL};
       PyObject *first = NULL, *last = NULL;

       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist,
                                        &first, &last,
                                        &self->number))
           return -1;

       if (first) {
           Py_SETREF(self->first, Py_NewRef(first));
       }
       if (last) {
           Py_SETREF(self->last, Py_NewRef(last));
       }
       return 0;
   }

   static PyMemberDef Custom_members[] = {
       {"number", Py_T_INT, offsetof(CustomObject, number), 0,
        "独自の数値"},
       {NULL}  /* 番兵 */
   };

   static PyObject *
   Custom_getfirst(PyObject *op, void *closure)
   {
       CustomObject *self = (CustomObject *) op;
       return Py_NewRef(self->first);
   }

   static int
   Custom_setfirst(PyObject *op, PyObject *value, void *closure)
   {
       CustomObject *self = (CustomObject *) op;
       if (value == NULL) {
           PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
           return -1;
       }
       if (!PyUnicode_Check(value)) {
           PyErr_SetString(PyExc_TypeError,
                           "The first attribute value must be a string");
           return -1;
       }
       Py_SETREF(self->first, Py_NewRef(value));
       return 0;
   }

   static PyObject *
   Custom_getlast(PyObject *op, void *closure)
   {
       CustomObject *self = (CustomObject *) op;
       return Py_NewRef(self->last);
   }

   static int
   Custom_setlast(PyObject *op, PyObject *value, void *closure)
   {
       CustomObject *self = (CustomObject *) op;
       if (value == NULL) {
           PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute");
           return -1;
       }
       if (!PyUnicode_Check(value)) {
           PyErr_SetString(PyExc_TypeError,
                           "The last attribute value must be a string");
           return -1;
       }
       Py_SETREF(self->last, Py_NewRef(value));
       return 0;
   }

   static PyGetSetDef Custom_getsetters[] = {
       {"first", Custom_getfirst, Custom_setfirst,
        "ファーストネーム", NULL},
       {"last", Custom_getlast, Custom_setlast,
        "ラストネーム", NULL},
       {NULL}  /* 番兵 */
   };

   static PyObject *
   Custom_name(PyObject *op, PyObject *Py_UNUSED(dummy))
   {
       CustomObject *self = (CustomObject *) op;
       return PyUnicode_FromFormat("%S %S", self->first, self->last);
   }

   static PyMethodDef Custom_methods[] = {
       {"name", Custom_name, METH_NOARGS,
        "ファーストネームとラストネームを連結した名前を返す"
       },
       {NULL}  /* 番兵 */
   };

   static PyTypeObject CustomType = {
       .ob_base = PyVarObject_HEAD_INIT(NULL, 0)
       .tp_name = "custom3.Custom",
       .tp_doc = PyDoc_STR("Custom オブジェクト"),
       .tp_basicsize = sizeof(CustomObject),
       .tp_itemsize = 0,
       .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
       .tp_new = Custom_new,
       .tp_init = Custom_init,
       .tp_dealloc = Custom_dealloc,
       .tp_members = Custom_members,
       .tp_methods = Custom_methods,
       .tp_getset = Custom_getsetters,
   };

   static int
   custom_module_exec(PyObject *m)
   {
       if (PyType_Ready(&CustomType) < 0) {
           return -1;
       }

       if (PyModule_AddObjectRef(m, "Custom", (PyObject *) &CustomType) < 0) {
           return -1;
       }

       return 0;
   }

   static PyModuleDef_Slot custom_module_slots[] = {
       {Py_mod_exec, custom_module_exec},
       {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},
       {0, NULL}
   };

   static PyModuleDef custom_module = {
       .m_base = PyModuleDef_HEAD_INIT,
       .m_name = "custom3",
       .m_doc = "拡張型を作成するサンプルモジュール。",
       .m_size = 0,
       .m_slots = custom_module_slots,
   };

   PyMODINIT_FUNC
   PyInit_custom3(void)
   {
       return PyModuleDef_Init(&custom_module);
   }

"first" と "last" 属性をもっと細かく制御するため、独自の getter 関数と
setter 関数を使います。 "first" 属性を取得、設定する関数は次のとおりで
す。

   static PyObject *
   Custom_getfirst(PyObject *op, void *closure)
   {
       CustomObject *self = (CustomObject *) op;
       Py_INCREF(self->first);
       return self->first;
   }

   static int
   Custom_setfirst(PyObject *op, PyObject *value, void *closure)
   {
       CustomObject *self = (CustomObject *) op;
       PyObject *tmp;
       if (value == NULL) {
           PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
           return -1;
       }
       if (!PyUnicode_Check(value)) {
           PyErr_SetString(PyExc_TypeError,
                           "The first attribute value must be a string");
           return -1;
       }
       tmp = self->first;
       Py_INCREF(value);
       self->first = value;
       Py_DECREF(tmp);
       return 0;
   }

getter 関数には、"Custom" オブジェクトと、void ポインタである「クロー
ジャ」を渡します。 ここではクロージャを無視します。 (クロージャは、定
義に関するデータを getter や setter に渡す高度な使い方をサポートします
。 例えば、クロージャ内のデータに応じて取得や設定を行う属性を決める、
一組の getter 関数と setter 関数を用意できます。)

setter 関数には、"Custom" オブジェクト、新しい値、クロージャを渡します
。 新しい値が "NULL" の場合は、属性の削除を意味します。 今回の setter
では、属性を削除しようとした場合や、新しい値が文字列でない場合にエラー
を送出します。

ここでは "PyGetSetDef" 構造体の配列をつくります:

   static PyGetSetDef Custom_getsetters[] = {
       {"first", Custom_getfirst, Custom_setfirst,
        "ファーストネーム", NULL},
       {"last", Custom_getlast, Custom_setlast,
        "ラストネーム", NULL},
       {NULL}  /* 番兵 */
   };

そしてこれを "tp_getset" スロットに登録します:

   .tp_getset = Custom_getsetters,

"PyGetSetDef" 構造体の最後の項目は、先ほど説明した「クロージャ」です。
ここではクロージャを使わないので、単に "NULL" を渡します。

また、メンバ定義からはこれらの属性を除いておきましょう:

   static PyMemberDef Custom_members[] = {
       {"number", Py_T_INT, offsetof(CustomObject, number), 0,
        "独自の数値"},
       {NULL}  /* 番兵 */
   };

また、ここでは "tp_init" ハンドラも渡されるものとして文字列のみを許可
するように修正する必要があります [3]:

   static int
   Custom_init(PyObject *op, PyObject *args, PyObject *kwds)
   {
       CustomObject *self = (CustomObject *) op;
       static char *kwlist[] = {"first", "last", "number", NULL};
       PyObject *first = NULL, *last = NULL, *tmp;

       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist,
                                        &first, &last,
                                        &self->number))
           return -1;

       if (first) {
           tmp = self->first;
           Py_INCREF(first);
           self->first = first;
           Py_DECREF(tmp);
       }
       if (last) {
           tmp = self->last;
           Py_INCREF(last);
           self->last = last;
           Py_DECREF(tmp);
       }
       return 0;
   }

これらの変更により、"first" と "last" メンバが "NULL" にならないことを
保証できるため、ほとんどの場合は "NULL" のチェックを削除できます。 つ
まり、"Py_XDECREF()" の呼び出しのほとんどを "Py_DECREF()" に置き換えら
れます。 唯一置き換えられないのは "tp_dealloc" の実装内です。 "tp_new"
でこれらのメンバの初期化に失敗した可能性があるためです。

さて、先ほどもしたように、このモジュール初期化関数と初期化関数内にある
モジュール名を変更しましょう。そして "setup.py" ファイルに追加の定義を
くわえます。


循環ガベージコレクションをサポートする
======================================

Python は *循環ガベージコレクタ (GC) 機能* をもっており、これは不要な
オブジェクトを、たとえ参照カウントがゼロでなくても発見することができま
す。そのような状況はオブジェクトの参照が循環しているときに起こりえます
。たとえば以下の例を考えてください:

   >>> l = []
   >>> l.append(l)
   >>> del l

この例では、自分自身をふくむリストを作りました。たとえこのリストを 削
除しても、それは自分自身への参照をまだ持ちつづけますから、参照カウント
はゼロにはなりません。嬉しいことに Python には循環ガベージコレクタは最
終的にはこのリストが不要であることを検出し、解放できます。

"Custom" の例の第 2 版では、"first" と "last" 属性にどのようなオブジェ
クトでも格納できるようにしました [4]。 さらに、第 2 版と第 3 版では
"Custom" のサブクラス化を許可しました。 サブクラスには任意の属性を追加
できます。 これらのどちらの理由によっても、"Custom" オブジェクトが参照
の循環に加わる可能性があります。

   >>> import custom3
   >>> class Derived(custom3.Custom): pass
   ...
   >>> n = Derived()
   >>> n.some_attribute = n

参照の循環に加わった "Custom" インスタンスを循環 GC が正しく検出して回
収できるようにするには、"Custom" 型でさらに二つのスロットを設定し、そ
れらのスロットを有効にするフラグを設定する必要があります。

   #define PY_SSIZE_T_CLEAN
   #include <Python.h>
   #include <stddef.h> /* offsetof() 用 */

   typedef struct {
       PyObject_HEAD
       PyObject *first; /* ファーストネーム */
       PyObject *last;  /* ラストネーム */
       int number;
   } CustomObject;

   static int
   Custom_traverse(PyObject *op, visitproc visit, void *arg)
   {
       CustomObject *self = (CustomObject *) op;
       Py_VISIT(self->first);
       Py_VISIT(self->last);
       return 0;
   }

   static int
   Custom_clear(PyObject *op)
   {
       CustomObject *self = (CustomObject *) op;
       Py_CLEAR(self->first);
       Py_CLEAR(self->last);
       return 0;
   }

   static void
   Custom_dealloc(PyObject *op)
   {
       PyObject_GC_UnTrack(op);
       (void)Custom_clear(op);
       Py_TYPE(op)->tp_free(op);
   }

   static PyObject *
   Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
   {
       CustomObject *self;
       self = (CustomObject *) type->tp_alloc(type, 0);
       if (self != NULL) {
           self->first = Py_GetConstant(Py_CONSTANT_EMPTY_STR);
           if (self->first == NULL) {
               Py_DECREF(self);
               return NULL;
           }
           self->last = Py_GetConstant(Py_CONSTANT_EMPTY_STR);
           if (self->last == NULL) {
               Py_DECREF(self);
               return NULL;
           }
           self->number = 0;
       }
       return (PyObject *) self;
   }

   static int
   Custom_init(PyObject *op, PyObject *args, PyObject *kwds)
   {
       CustomObject *self = (CustomObject *) op;
       static char *kwlist[] = {"first", "last", "number", NULL};
       PyObject *first = NULL, *last = NULL;

       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist,
                                        &first, &last,
                                        &self->number))
           return -1;

       if (first) {
           Py_SETREF(self->first, Py_NewRef(first));
       }
       if (last) {
           Py_SETREF(self->last, Py_NewRef(last));
       }
       return 0;
   }

   static PyMemberDef Custom_members[] = {
       {"number", Py_T_INT, offsetof(CustomObject, number), 0,
        "独自の数値"},
       {NULL}  /* 番兵 */
   };

   static PyObject *
   Custom_getfirst(PyObject *op, void *closure)
   {
       CustomObject *self = (CustomObject *) op;
       return Py_NewRef(self->first);
   }

   static int
   Custom_setfirst(PyObject *op, PyObject *value, void *closure)
   {
       CustomObject *self = (CustomObject *) op;
       if (value == NULL) {
           PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
           return -1;
       }
       if (!PyUnicode_Check(value)) {
           PyErr_SetString(PyExc_TypeError,
                           "The first attribute value must be a string");
           return -1;
       }
       Py_XSETREF(self->first, Py_NewRef(value));
       return 0;
   }

   static PyObject *
   Custom_getlast(PyObject *op, void *closure)
   {
       CustomObject *self = (CustomObject *) op;
       return Py_NewRef(self->last);
   }

   static int
   Custom_setlast(PyObject *op, PyObject *value, void *closure)
   {
       CustomObject *self = (CustomObject *) op;
       if (value == NULL) {
           PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute");
           return -1;
       }
       if (!PyUnicode_Check(value)) {
           PyErr_SetString(PyExc_TypeError,
                           "The last attribute value must be a string");
           return -1;
       }
       Py_XSETREF(self->last, Py_NewRef(value));
       return 0;
   }

   static PyGetSetDef Custom_getsetters[] = {
       {"first", Custom_getfirst, Custom_setfirst,
        "ファーストネーム", NULL},
       {"last", Custom_getlast, Custom_setlast,
        "ラストネーム", NULL},
       {NULL}  /* 番兵 */
   };

   static PyObject *
   Custom_name(PyObject *op, PyObject *Py_UNUSED(dummy))
   {
       CustomObject *self = (CustomObject *) op;
       return PyUnicode_FromFormat("%S %S", self->first, self->last);
   }

   static PyMethodDef Custom_methods[] = {
       {"name", Custom_name, METH_NOARGS,
        "ファーストネームとラストネームを連結した名前を返す"
       },
       {NULL}  /* 番兵 */
   };

   static PyTypeObject CustomType = {
       .ob_base = PyVarObject_HEAD_INIT(NULL, 0)
       .tp_name = "custom4.Custom",
       .tp_doc = PyDoc_STR("Custom オブジェクト"),
       .tp_basicsize = sizeof(CustomObject),
       .tp_itemsize = 0,
       .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
       .tp_new = Custom_new,
       .tp_init = Custom_init,
       .tp_dealloc = Custom_dealloc,
       .tp_traverse = Custom_traverse,
       .tp_clear = Custom_clear,
       .tp_members = Custom_members,
       .tp_methods = Custom_methods,
       .tp_getset = Custom_getsetters,
   };

   static int
   custom_module_exec(PyObject *m)
   {
       if (PyType_Ready(&CustomType) < 0) {
           return -1;
       }

       if (PyModule_AddObjectRef(m, "Custom", (PyObject *) &CustomType) < 0) {
           return -1;
       }

       return 0;
   }

   static PyModuleDef_Slot custom_module_slots[] = {
       {Py_mod_exec, custom_module_exec},
       {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},
       {0, NULL}
   };

   static PyModuleDef custom_module = {
       .m_base = PyModuleDef_HEAD_INIT,
       .m_name = "custom4",
       .m_doc = "拡張型を作成するサンプルモジュール。",
       .m_size = 0,
       .m_slots = custom_module_slots,
   };

   PyMODINIT_FUNC
   PyInit_custom4(void)
   {
       return PyModuleDef_Init(&custom_module);
   }

まず、走査メソッドによって、参照の循環に加わる可能性のある子オブジェク
トを循環 GC に知らせます。

   static int
   Custom_traverse(PyObject *op, visitproc visit, void *arg)
   {
       CustomObject *self = (CustomObject *) op;
       int vret;
       if (self->first) {
           vret = visit(self->first, arg);
           if (vret != 0)
               return vret;
       }
       if (self->last) {
           vret = visit(self->last, arg);
           if (vret != 0)
               return vret;
       }
       return 0;
   }

参照の循環に加わる可能性のある子オブジェクトごとに、走査メソッドに渡さ
れた "visit()" 関数を呼び出す必要があります。 "visit()" 関数は、子オブ
ジェクトと、走査メソッドに渡された追加の引数 "arg" を受け取ります。 戻
り値は整数で、ゼロでなければその値をそのまま返す必要があります。

Python には、visit 関数の呼び出しを自動化する "Py_VISIT()" マクロがあ
ります。 "Py_VISIT()" を使うと、"Custom_traverse" の定型的なコードを最
小限にできます。

   static int
   Custom_traverse(PyObject *op, visitproc visit, void *arg)
   {
       CustomObject *self = (CustomObject *) op;
       Py_VISIT(self->first);
       Py_VISIT(self->last);
       return 0;
   }

注釈:

  "Py_VISIT()" を使うには、"tp_traverse" の実装で、引数の名前を必ず
  "visit" と "arg" にする必要があります。

次に、参照の循環に加わる可能性のある子オブジェクトをすべてクリアするメ
ソッドを用意する必要があります。

   static int
   Custom_clear(PyObject *op)
   {
       CustomObject *self = (CustomObject *) op;
       Py_CLEAR(self->first);
       Py_CLEAR(self->last);
       return 0;
   }

"Py_CLEAR()" マクロを使っていることに注目してください。 これは、参照カ
ウントを減らしながら任意の型のデータ属性をクリアする、推奨される安全な
方法です。 属性を "NULL" に設定する前に、代わりに "Py_XDECREF()" を呼
び出すと、属性のデストラクタがその属性を再び読み取るコードを呼び出す可
能性があります (参照の循環がある場合は *特に* 注意が必要です)。

注釈:

  "Py_CLEAR()" と同じ処理は、次のようにも書けます。

     PyObject *tmp;
     tmp = self->first;
     self->first = NULL;
     Py_XDECREF(tmp);

  それでも、属性を削除するときは常に "Py_CLEAR()" を使う方が、はるかに
  簡単で間違いも少なくなります。 堅牢性を犠牲にしてまで細かな最適化を
  試みないでください。

メモリ解放関数 "Custom_dealloc" は、属性のクリア時に任意のコードを呼び
出す可能性があります。 つまり、この関数内で循環 GC が実行される可能性
があります。 GC は参照カウントがゼロでないことを前提としているため、メ
ンバをクリアする前に "PyObject_GC_UnTrack()" を呼び出して、GC の追跡対
象からオブジェクトを外す必要があります。 "PyObject_GC_UnTrack()" と
"Custom_clear" を使って書き直したメモリ解放関数は次のとおりです。

   static void
   Custom_dealloc(PyObject *op)
   {
       PyObject_GC_UnTrack(op);
       (void)Custom_clear(op);
       Py_TYPE(op)->tp_free(op);
   }

最後に、クラスのフラグに "Py_TPFLAGS_HAVE_GC" フラグを追加します。

   .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,

これで完了です。 "tp_alloc" スロットまたは "tp_free" ハンドラが書かれ
ていれば、それらを循環ガベージコレクションに使えるよう修正すればよいの
です。ほとんどの拡張機能は自動的に提供されるバージョンを使うでしょう。


他の型のサブクラスを作る
========================

既存の型を継承した新しい拡張型を作成することができます。組み込み型から
継承するのは特に簡単です。必要な "PyTypeObject" を簡単に利用できるから
です。それに比べて、 "PyTypeObject" 構造体を拡張モジュール間で共有する
のは難しいです。

この例では、組み込みの "list" 型を継承した "SubList" 型を作成します。
新しい型は通常のリストと完全な互換性を持ち、さらに内部カウンタを増やす
"increment()" メソッドを持ちます。

   >>> import sublist
   >>> s = sublist.SubList(range(3))
   >>> s.extend(s)
   >>> print(len(s))
   6
   >>> print(s.increment())
   1
   >>> print(s.increment())
   2

   #define PY_SSIZE_T_CLEAN
   #include <Python.h>

   typedef struct {
       PyListObject list;
       int state;
   } SubListObject;

   static PyObject *
   SubList_increment(PyObject *op, PyObject *Py_UNUSED(dummy))
   {
       SubListObject *self = (SubListObject *) op;
       self->state++;
       return PyLong_FromLong(self->state);
   }

   static PyMethodDef SubList_methods[] = {
       {"increment", SubList_increment, METH_NOARGS,
        PyDoc_STR("状態カウンタを増やす")},
       {NULL},
   };

   static int
   SubList_init(PyObject *op, PyObject *args, PyObject *kwds)
   {
       SubListObject *self = (SubListObject *) op;
       if (PyList_Type.tp_init(op, args, kwds) < 0)
           return -1;
       self->state = 0;
       return 0;
   }

   static PyTypeObject SubListType = {
       .ob_base = PyVarObject_HEAD_INIT(NULL, 0)
       .tp_name = "sublist.SubList",
       .tp_doc = PyDoc_STR("SubList オブジェクト"),
       .tp_basicsize = sizeof(SubListObject),
       .tp_itemsize = 0,
       .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
       .tp_init = SubList_init,
       .tp_methods = SubList_methods,
   };

   static int
   sublist_module_exec(PyObject *m)
   {
       SubListType.tp_base = &PyList_Type;
       if (PyType_Ready(&SubListType) < 0) {
           return -1;
       }

       if (PyModule_AddObjectRef(m, "SubList", (PyObject *) &SubListType) < 0) {
           return -1;
       }

       return 0;
   }

   static PyModuleDef_Slot sublist_module_slots[] = {
       {Py_mod_exec, sublist_module_exec},
       {Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},
       {0, NULL}
   };

   static PyModuleDef sublist_module = {
       .m_base = PyModuleDef_HEAD_INIT,
       .m_name = "sublist",
       .m_doc = "拡張型を作成するサンプルモジュール。",
       .m_size = 0,
       .m_slots = sublist_module_slots,
   };

   PyMODINIT_FUNC
   PyInit_sublist(void)
   {
       return PyModuleDef_Init(&sublist_module);
   }

見てのとおり、ソースコードは前の節の "Custom" の例によく似ています。
主な違いを順に見ていきましょう。

   typedef struct {
       PyListObject list;
       int state;
   } SubListObject;

派生型のオブジェクトで最も大きな違いは、先頭のメンバを基底型のオブジェ
クト構造体にする必要があることです。 基底型の構造体には、すでに先頭に
"PyObject_HEAD()" が含まれています。

Python オブジェクトが "SubList" のインスタンスである場合、その
"PyObject *" ポインタは "PyListObject *" と "SubListObject *" のどちら
にも安全にキャストできます。

   static int
   SubList_init(PyObject *op, PyObject *args, PyObject *kwds)
   {
       SubListObject *self = (SubListObject *) op;
       if (PyList_Type.tp_init(op, args, kwds) < 0)
           return -1;
       self->state = 0;
       return 0;
   }

上の例は、基底型の "__init__()" メソッドを呼び出す方法を示しています。

この方法は、独自の "tp_new" と "tp_dealloc" メンバを持つ型を書くときに
重要です。 "tp_new" ハンドラでは、自身の "tp_alloc" でオブジェクトのメ
モリを割り当てるのではなく、基底クラスの "tp_new" を呼び出して、基底ク
ラスに処理を任せるべきです。

"PyTypeObject" 構造体には、型の具体的な基底クラスを指定する "tp_base"
があります。 プラットフォーム間のコンパイラの違いによる問題があるため
、このフィールドに "PyList_Type" への参照を直接設定することはできませ
ん。 "Py_mod_exec" 関数内で設定してください。

   static int
   sublist_module_exec(PyObject *m)
   {
       SubListType.tp_base = &PyList_Type;
       if (PyType_Ready(&SubListType) < 0) {
           return -1;
       }

       if (PyModule_AddObjectRef(m, "SubList", (PyObject *) &SubListType) < 0) {
           return -1;
       }

       return 0;
   }

"PyType_Ready()" を呼び出す前に、型の構造体の "tp_base" スロットを設定
しておく必要があります。 既存の型から派生させる場合、"tp_alloc" スロッ
トを "PyType_GenericNew()" で設定する必要はありません。 基底型の割り当
て関数が継承されます。

その後の "PyType_Ready()" の呼び出しと型オブジェクトのモジュールへの追
加は、基本的な "Custom" の例と同じです。

-[ 脚注 ]-

[1] これはそのオブジェクトが文字列や実数などの基本タイプであるような時
    に成り立ちます。

[2] この例の "tp_dealloc" ハンドラでは、型がガベージコレクションをサポ
    ートしていないため、この点を利用しました。

[3] "first" と "last" メンバが文字列だと分かったので、参照カウントを減
    らすときの注意を少し省けるかもしれません。 しかし、ここでは文字列
    のサブクラスのインスタンスも受け付けます。 通常の文字列の解放が自
    分のオブジェクトを呼び戻すことはありませんが、文字列のサブクラスの
    インスタンスを解放するときにもそうならないとは保証できません。

[4] また、属性を文字列のインスタンスに制限しても、ユーザーは任意の
    "str" サブクラスを渡せるので、依然として参照の循環を作れます。
