2.2.3.2 特定の型に特化した属性の管理

話を単純にするため、ここでは char* を使ったバージョンのみを 示します。name パラメータの型はインターフェイスとして char* を使うか PyObject* を使うかの違いしかありません。 この例では、上の総称的な例と同じことを効率的にやりますが、 Python 2.2 で追加された総称的な型のサポートを使わずにやります。 これを紹介することは 2つの意味をもっています。ひとつはどうやって、 古いバージョンの Python と互換性のあるやり方で、基本的な属性管理を おこなうか。そしてもうひとつはハンドラの関数がどのようにして呼ばれるのか。 これで、たとえその機能を拡張する必要があるとき、何をどうすればいいか わかるでしょう。

tp_getattr ハンドラはオブジェクトが属性への参照を要求するときに 呼ばれます。 これは、そのクラスの __getattr__() メソッドが呼ばれるであろう状況と 同じ状況下で呼び出されます。

これを処理するありがちな方法は、(1) 一連の関数 (下の例の newdatatype_getSize()newdatatype_setSize()) を実装する、(2) これらの関数を記録したメソッドテーブルを提供する、 そして (3) そのテーブルの参照結果を返す getattr 関数を提供することです。 メソッドテーブルはタイプオブジェクトの tp_methods メンバと 同じ構造を持っています。

以下に例を示します:

static PyMethodDef newdatatype_methods[] = {
    {"getSize", (PyCFunction)newdatatype_getSize, METH_VARARGS,
     "Return the current size."},
    {"setSize", (PyCFunction)newdatatype_setSize, METH_VARARGS,
     "Set the size."},
    {NULL, NULL, 0, NULL}           /* 見張り */
};

static PyObject *
newdatatype_getattr(newdatatypeobject *obj, char *name)
{
    return Py_FindMethod(newdatatype_methods, (PyObject *)obj, name);
}

tp_setattr ハンドラは、クラスのインスタンスの __setattr__() または __delattr__() メソッドが呼ばれるであろう 状況で呼び出されます。ある属性が削除されるとき、3番目のパラメータは NULLに なります。以下の例はたんに例外を発生させるものですが、もし本当にこれと 同じことをしたいなら、tp_setattr ハンドラを NULLに設定すべきです。

static int
newdatatype_setattr(newdatatypeobject *obj, char *name, PyObject *v)
{
    (void)PyErr_Format(PyExc_RuntimeError, "Read-only attribute: \%s", name);
    return -1;
}

ご意見やご指摘をお寄せになりたい方は、 このドキュメントについて... をご覧ください。