### 2.2.3.1 総称的な属性を管理する

バージョン2.2 以降で新規追加された 仕様です。

ほとんどの型は単純な属性を使うだけです。では、 どのような属性が単純だといえるのでしょうか? それが満たすべき条件はごくわずかです:

1. `PyType_Ready()` が呼ばれたとき、すでに 属性の名前がわかっていること。

2. 属性を参照したり設定したりするときに、特別な 記録のための処理が必要でなく、また参照したり設定した値に対して どんな操作も実行する必要がないこと。

これらの条件は、属性の値や、値が計算されるタイミング、 または格納されたデータがどの程度妥当なものであるかといったことに なんら制約を課すものではないことに注意してください。

`PyType_Ready()` が呼ばれると、これはそのタイプオブジェクトに 参照されている 3つのテーブルを使って、そのタイプオブジェクトの辞書中に デスクリプタ を作成します。各デスクリプタは、インスタンスオブジェクトの属性に 対するアクセスを制御します。それぞれのテーブルはなくてもかまいません。 もしこれら 3つがすべて `NULL`だと、その型のインスタンスはその基底型から 継承した属性だけを持つことになります。また、`tp_getattro` および `tp_setattro` が `NULL` のままだった場合も、 基底型にこれらの属性の操作がまかせられます。

テーブルはタイプオブジェクト中の 3つのメンバとして宣言されています:

        struct PyMethodDef *tp_methods;
        struct PyMemberDef *tp_members;
        struct PyGetSetDef *tp_getset;

`tp_methods` が `NULL`でない場合、 これは `PyMethodDef` 構造体への配列を指している必要があります。 テーブル中の各エントリは、つぎのような構造体のインスタンスです:

    typedef struct PyMethodDef {
        char        *ml_name;       /* メソッド名 */
        PyCFunction  ml_meth;       /* 実装する関数 */
        int	         ml_flags;      /* フラグ */
        char        *ml_doc;        /* docstring */
    } PyMethodDef;

その型が提供する各メソッドについてひとつのエントリを定義する必要があります。 基底型から継承してきたメソッドについてはエントリは必要ありません。 これの最後には、配列の終わりを示すための見張り番 (sentinel) として 追加のエントリがひとつ必要です。この場合、`ml_name` メンバが sentinel として使われ、 その値は `NULL`でなければなりません。

2番目のテーブルは、インスタンス中に格納されるデータと直接対応づけられた属性を 定義するのに使います。いくつもの C の原始的な型がサポートされており、 アクセスを読み込み専用にも読み書き可能にもできます。 このテーブルで使われる構造体は次のように定義されています:

    typedef struct PyMemberDef {
        char *name;
        int   type;
        int   offset;
        int   flags;
        char *doc;
    } PyMemberDef;

このテーブルの各エントリに対してデスクリプタが作成され、 値をインスタンスの構造体から抽出しうる型に対してそれらが追加されます。 `type` メンバは structmember.h ヘッダで定義された 型のコードをひとつ含んでいる必要があります。この値は Python における 値と C における値をどのように変換しあうかを定めるものです。 `flags` メンバはこの属性がどのようにアクセスされるかを制御する フラグを格納するのに使われます。

以下のフラグ用定数は structmember.h で定義されており、 これらはビットごとの OR を取って組み合わせられます。

Constant | Meaning
--- | ---
`READONLY` | 絶対に変更できない。
`RO` | `READONLY` の短縮形。
`READ_RESTRICTED` | 制限モード (restricted mode) では参照できない。
`WRITE_RESTRICTED` | 制限モード (restricted mode) では変更できない。
`RESTRICTED` | 制限モード (restricted mode) では参照も変更もできない。

`tp_members` を使ったひとつの面白い利用法は、実行時に使われる デスクリプタを作成しておき、単にテーブル中にテキストを置いておくことによって、 この方法で定義されるどの属性は対応した docstring を持つことができるように することです。 アプリケーションはこのイントロスペクション用 API を使って、 クラスオブジェクトからデスクリプタを取り出し、その `__doc__` 属性を 使って docstring を得られます。

`tp_methods` テーブルと同じように、ここでも `name` メンバの値を `NULL` にした見張り用エントリが必要です。