新スタイルの型を定義する構造体: PyTypeObject 構造体は、おそらく Python オブジェクトシステムの中で最も重要な構造体の一つでしょう。 型オブジェクトはPyObject_*() 系や PyType_*() 系の関数で扱えますが、ほとんどの Python アプリケーションにとって、 さして面白みのある機能を提供しません。 とはいえ、型オブジェクトはオブジェクトがどのように振舞うかを決める 基盤ですから、インタプリタ自体や新たな型を定義する拡張モジュールでは 非常に重要な存在です。
型オブジェクトは標準の型 (standard type) に比べるとかなり大きな 構造体です。その理由は、型オブジェクトがある型の様々な機能を実現する 小さな機能単位を実装した C 関数へのポインタが大部分を占めるような 多数の値を保持しているからです。この節では、型オブジェクトの各 フィールドについて詳細を説明します。各フィールドは、構造体内で 出現する順番に説明されています。
Typedefs: unaryfunc, binaryfunc, ternaryfunc, inquiry, coercion, intargfunc, intintargfunc, intobjargproc, intintobjargproc, objobjargproc, destructor, freefunc, printfunc, getattrfunc, getattrofunc, setattrfunc, setattrofunc, cmpfunc, reprfunc, hashfunc
PyTypeObject の構造体定義はInclude/object.h で見つけられるはずです。参照の手間を省くために、ここでは 定義を繰り返します:
typedef struct _typeobject { PyObject_VAR_HEAD char *tp_name; /* For printing, in format "<module>.<name>" */ int tp_basicsize, tp_itemsize; /* For allocation */ /* Methods to implement standard operations */ destructor tp_dealloc; printfunc tp_print; getattrfunc tp_getattr; setattrfunc tp_setattr; cmpfunc tp_compare; reprfunc tp_repr; /* Method suites for standard classes */ PyNumberMethods *tp_as_number; PySequenceMethods *tp_as_sequence; PyMappingMethods *tp_as_mapping; /* More standard operations (here for binary compatibility) */ hashfunc tp_hash; ternaryfunc tp_call; reprfunc tp_str; getattrofunc tp_getattro; setattrofunc tp_setattro; /* Functions to access object as input/output buffer */ PyBufferProcs *tp_as_buffer; /* Flags to define presence of optional/expanded features */ long tp_flags; char *tp_doc; /* Documentation string */ /* Assigned meaning in release 2.0 */ /* call function for all accessible objects */ traverseproc tp_traverse; /* delete references to contained objects */ inquiry tp_clear; /* Assigned meaning in release 2.1 */ /* rich comparisons */ richcmpfunc tp_richcompare; /* weak reference enabler */ long tp_weaklistoffset; /* Added in release 2.2 */ /* Iterators */ getiterfunc tp_iter; iternextfunc tp_iternext; /* Attribute descriptor and subclassing stuff */ struct PyMethodDef *tp_methods; struct PyMemberDef *tp_members; struct PyGetSetDef *tp_getset; struct _typeobject *tp_base; PyObject *tp_dict; descrgetfunc tp_descr_get; descrsetfunc tp_descr_set; long tp_dictoffset; initproc tp_init; allocfunc tp_alloc; newfunc tp_new; freefunc tp_free; /* Low-level free-memory routine */ inquiry tp_is_gc; /* For PyObject_IS_GC */ PyObject *tp_bases; PyObject *tp_mro; /* method resolution order */ PyObject *tp_cache; PyObject *tp_subclasses; PyObject *tp_weaklist; } PyTypeObject;
型オブジェクト構造体はPyVarObject 構造体を拡張したものです。 ob_size フィールドは、(通常 class 文が呼び出す type_new() で生成される) 動的な型に使います。 PyType_Type (メタタイプ) はtp_itemsize を初期化するので 注意してください。すなわち、インスタンス (つまり型オブジェクト) には ob_size フィールドがなければなりません。
Py_TRACE_REFS
が定義されている
場合のみ存在します。PyObject_HEAD_INIT
マクロを使うと、
フィールドを NULL に初期化します。静的にメモリ確保されている
オブジェクトでは、これらのフィールドは常に NULLのままです。
動的にメモリ確保されるオブジェクトの場合、これら二つのフィールドは、
ヒープ上の全ての 存続中のオブジェクトからなる二重リンクリスト
でオブジェクトをリンクする際に使われます。
このことは様々なデバッグ目的に利用できます; 現状では、環境変数
PYTHONDUMPREFS が設定されているときに、プログラムの実行
終了時点で存続しているオブジェクトを出力するのが唯一の用例です。
サブタイプはこのフィールドを継承しません。
PyObject_HEAD_INIT
は
この値を 1
に初期化します。静的にメモリ確保された型オブジェクト
では、型のインスタンス (ob_type が該当する型を指している
オブジェクト) は参照をカウントする対象にはなりません。
動的にメモリ確保される型オブジェクトの場合、インスタンスは
参照カウントの対象になります。
サブタイプはこのフィールドを継承しません。
PyObject_HEAD_INIT
マクロで初期化され、通常は
&PyType_Type
になります。しかし、(少なくとも) Windows で
利用できる動的ロード可能な拡張モジュールでは、コンパイラは
有効な初期化ではないと文句をつけます。そこで、ならわしとして、
PyObject_HEAD_INIT
には NULL を渡して初期化しておき、
他の操作を行う前にモジュールの初期化関数で明示的にこのフィールドを
初期化することになっています。この操作は以下のように行います:
Foo_Type.ob_type = &PyType_Type;
上の操作は、該当する型のいかなるインスタンス生成よりも前に
しておかねばなりません。PyType_Ready() は
ob_type が NULLかどうか調べ、NULLの場合には
初期化します: Python 2.2 では、&PyType_Type
にセット
します; in Python 2.2.1 およびそれ以降では基底クラスの
ob_type フィールドに初期化します。
ob_type が非ゼロの場合、PyType_Ready() は
このフィールドを変更しません。
Python 2.2 では、サブタイプはこのフィールドを継承しません。 2.2.1 と 2.3 以降では、サブタイプはこのフィールドを継承します。
サブタイプはこのフィールドを継承しません。
"P.Q.M.T"
に
初期化します。
動的にメモリ確保される型オブジェクトの場合、このフィールドは
単に型の名前になり、モジュール名は型の辞書内でキー '__module__'
に対する値として明示的に保存されます。
静的にメモリ確保される型オブジェクトの場合、tp_name フィールド にはドットが入っているはずです。最後のドットよりも前にある 部分文字列全体は __module__ 属性として、また ドットよりも後ろにある部分は__name__ 属性としてアクセスできます。
ドットが入っていない場合、tp_name フィールドの内容全てが __name__ 属性になり、 __module__ 属性は (前述のように型の辞書内で明示的にセットしないかぎり) 未定義になります。 このため、こうした型オブジェクトは pickle 化できないことになります。
サブタイプはこのフィールドを継承しません。
型には二つの種類があります: 固定長インスタンスの型は、 tp_itemsize フィールドがゼロで、可変長インスタンスの方は tp_itemsize フィールドが非ゼロの値になります。 固定長インスタンスの型の場合、全てのインスタンスは等しく tp_basicsize で与えられたサイズになります。
可変長インスタンスの型の場合、インスタンスにはob_size
フィールドがなくてはならず、インスタンスのサイズは N をオブジェクトの
``長さ'' として、tp_basicsize と N かける tp_itemsize
の加算になります。N の値は通常、インスタンスの ob_size
フィールドに記憶されます。ただし例外がいくつかあります:
例えば、長整数では負の値を ob_size に使って、インスタンスの
表す値が負であることを示し、 N 自体は abs(ob_size)
になります。また、ob_size フィールドがあるからといって、
必ずしもインスタンスが可変長であることを意味しません (例えば、
リスト型の構造体は固定長のインスタンスになるにもかかわらず、
インスタンスにはちゃんと意味を持った ob_size フィールドが
あります)。
基本サイズには、PyObject_HEAD マクロまたは PyObject_VAR_HEAD マクロ (インスタンス構造体を 宣言するのに使ったどちらかのマクロ) で宣言されているフィールド が入っています。さらに、_ob_prev および _ob_next フィールドがある場合、これらのフィールドもサイズに加算されます。
従って、tp_basicsize の正しい初期化パラメタを得るには、 インスタンスデータのレイアウトを宣言するのに使う構造体に対して sizeof 演算子を使うしかありません。 基本サイズには、GC ヘッダサイズは入っていません (これは Python 2.2 からの新しい仕様です; 2.1 や 2.0 では、GC ヘッダサイズは tp_basicsize に入っていました)。
バイト整列 (alignment) に関する注釈: 変数の各要素を配置する際に特定の
バイト整列が必要となる場合、tp_basicsize の値に
気をつけなければなりません。一例: 例えばある型がdouble
の
配列を実装しているとします。tp_itemsize は
sizeof(double)
です。(double
のバイト整列条件に従って)
tp_basicsize がsizeof(double)
の個数分のサイズに
なるようにするのはプログラマの責任です。
None
やEllipsis
の場合のように、インスタンスが
決してメモリ解放されない型でない限り) 必ず定義しなければなりません。
デストラクタ関数は、Py_DECREF() や Py_XDECREF() マクロで、操作後の参照カウントがゼロになった際に呼び出されます。 呼び出された時点では、インスタンスはまだ存在しますが、インスタンスに 対する参照は全ない状態です。デストラクタ関数はインスタンスが保持している 全ての参照を解放し、インスタンスが確保している全てのメモリバッファを (バッファの確保時に使った関数に対応するメモリ解放関数を使って) 解放し、最後に (かならず最後に行う操作として) その型の tp_free 関数を呼び出します。ある型がサブタイプを作成できない (Py_TPFLAGS_BASETYPE フラグがセットされていない) 場合、 tp_free の代わりにオブジェクトのメモリ解放関数 (deallocator) を 直接呼び出してもかまいません。オブジェクトのメモリ解放関数は、 インスタンスのメモリ確保を行う際に使った関数と同じファミリでなければ なりません; インスタンスを PyObject_New() や PyObject_VarNew() でメモリ確保した場合には、通常 PyObject_Del() を使い、PyObject_GC_New() や PyObject_GC_VarNew() で確保した場合には PyObject_GC_Del() を使います。
サブタイプはこのフィールドを継承します。
出力関数は、インスタンスが 実体のある (real) ファイルに出力 される場合にのみ呼び出されます; (StringIO インスタンスのような) 擬似ファイルに出力される場合には、インスタンスの tp_repr や tp_str が指す関数が呼び出され、文字列への変換を行います。 また、tp_print が NULLの場合にもこれらの関数が呼び出され ます。 tp_repr や tp_str と異なる出力を生成するような tp_print は、決して型に実装してはなりません。
出力関数はPyObject_Print() と同じシグネチャ:
int tp_print(PyObject *self, FILE *file, int flags)
で呼び出されます。self 引数は出力するインスタンスを指します。
file 引数は出力先となる標準入出力 (stdio) ファイルです。
flags 引数はフラグビットを組み合わせた値です。
現在定義されているフラグビットは Py_PRINT_RAW のみです。
Py_PRINT_RAW フラグビットがセットされていれば、
インスタンスはtp_str と同じ書式で出力されます。
Py_PRINT_RAW フラグビットがクリアならば、
インスタンスはtp_repr と同じ書式で出力されます。
この関数は、操作中にエラーが生じた場合、-1
を返して例外状態を
セットしなければなりません。
tp_print フィールドは撤廃されるかもしれません。いずれにせよ、 tp_print は定義せず、代わりにtp_repr や tp_str に頼って出力を行うようにしてください。
サブタイプはこのフィールドを継承します。
このフィールドは撤廃されています。このフィールドを定義する場合、 tp_getattro 関数と同じように動作し、属性名は Python 文字列 オブジェクトではなく C 文字列で指定するような関数を指すように しなければなりません。シグネチャは PyObject_GetAttrString() と同じです。
このフィールドはtp_getattro と共にサブタイプに継承 されます: すなわち、サブタイプのtp_getattr および tp_getattro が共に NULLの場合、サブタイプは 基底タイプからtp_getattr と tp_getattro を一緒に 継承します。
このフィールドは撤廃されています。このフィールドを定義する場合、 tp_setattro 関数と同じように動作し、属性名は Python 文字列 オブジェクトではなく C 文字列で指定するような関数を指すように しなければなりません。シグネチャは PyObject_SetAttrString() と同じです。
このフィールドはtp_setattro と共にサブタイプに継承 されます: すなわち、サブタイプのtp_setattr および tp_setattro が共に NULLの場合、サブタイプは 基底タイプからtp_setattr と tp_setattro を一緒に 継承します。
シグネチャはPyObject_Compare() と同じです。
この関数は self が other よりも大きければ 1
、
self と other の値が等しければ 0
、
self が other より小さければ -1
を返します。
この関数は、比較操作中にエラーが生じた場合、例外状態をセットして
-1
を返さねばなりません。
このフィールドはtp_richcompare およびtp_hash と共にサブタイプに継承されます: すなわち、サブタイプの tp_compare 、tp_richcompare および tp_hash が共に NULLの場合、サブタイプは 基底タイプからtp_compare、tp_richcompare、 tp_hash の三つを一緒に継承します。
シグネチャはPyObject_Repr() と同じです。 この関数は文字列オブジェクトか Unicode オブジェクトを返さねば なりません。理想的には、この関数が返す文字列は、適切な環境で eval() に渡した場合、同じ値を持つオブジェクトになるような 文字列でなければなりません。不可能な場合には、オブジェクトの型と 値から導出した内容の入った "<" から始まって ">" で終わる文字列を返さねば なりません。
このフィールドが設定されていない場合、"<%s object at %p>"
の形式をとる文字列が返されます。 %s
は型の名前に、
%p
はオブジェクトのメモリアドレスに置き換えられます。
サブタイプはこのフィールドを継承します。
PyNumberMethods *tp_as_number;
XXX
PySequenceMethods *tp_as_sequence;
XXX
PyMappingMethods *tp_as_mapping;
XXX
シグネチャはPyObject_Hash() と同じです。
この関数は C の long 型の値を返さねばなりません。
通常時には -1
を戻り値にしてはなりません; ハッシュ値の
計算中にエラーが生じた場合、関数は例外をセットして-1
を
返さねばなりません。
このフィールドが設定されていない場合、二つの可能性があります: tp_compare および tp_richcompare フィールドの 両方が NULLの場合、オブジェクトのアドレスに基づいたデフォルトの ハッシュ値が返されます; それ以外の場合、TypeError が送出されます。
このフィールドはtp_compare およびtp_richcompare と共にサブタイプに継承されます: すなわち、サブタイプの tp_compare 、tp_richcompare および tp_hash が共に NULLの場合、サブタイプは 基底タイプからtp_compare、tp_richcompare、 tp_hash の三つを一緒に継承します。
サブタイプはこのフィールドを継承します。
シグネチャはPyObject_Str() と同じです; この関数は文字列オブジェクトか Unicode オブジェクトを返さねばなりません。 また、この関数はオブジェクトを ``分かりやすく (friendly)'' 表現 した文字列を返さねばなりません。というのは、この文字列は print 文で使われることになる表記だからです。
このフィールドが設定されていない場合、文字列表現を返すためには PyObject_Repr() が呼び出されます。
サブタイプはこのフィールドを継承します。
シグネチャはPyObject_GetAttr() と同じです。 対する通常の属性検索を実装しているPyObject_GenericGetAttr() をこのフィールドに設定しておくと往々にして便利です。
このフィールドはtp_getattr と共にサブタイプに継承 されます: すなわち、サブタイプのtp_getattr および tp_getattro が共に NULLの場合、サブタイプは 基底タイプからtp_getattr と tp_getattro を一緒に 継承します。
シグネチャはPyObject_SetAttr() と同じです。 対する通常の属性設定を実装しているPyObject_GenericSetAttr() をこのフィールドに設定しておくと往々にして便利です。
このフィールドはtp_setattr と共にサブタイプに継承 されます: すなわち、サブタイプのtp_setattr および tp_setattro が共に NULLの場合、サブタイプは 基底タイプからtp_setattr と tp_setattro を一緒に 継承します。
tp_as_buffer フィールド自体は継承されませんが、フィールド内に 入っているフィールドは個別に継承されます。
このフィールドの継承は複雑です。ほとんどのフラグビットは 個別に継承されます。つまり、基底タイプであるフラグビットがセット されている場合、サブタイプはそのフラグビットを継承します。 機能拡張のための構造体に関するフラグビットは、その機能拡張構造体 が継承されるときに限定して継承されます。すなわち、基底タイプの フラグビットの値は、機能拡張構造体へのポインタと一緒にサブタイプに コピーされます。 Py_TPFLAGS_HAVE_GC フラグビットは、tp_traverse および tp_clear フィールドと合わせてコピーされます。 すなわち、サブタイプの Py_TPFLAGS_HAVE_GC フラグビットが クリアで、かつ (Py_TPFLAGS_HAVE_RICHCOMPARE フラグビットの 指定によって) tp_traverse および tp_clear フィールドがサブタイプ内に存在しており、かつ値が NULL の場合に 基底タイプから値を継承します。
以下のビットマスクは現在定義されているものです; フラグは|
演算子で論理和を取って tp_flags フィールドの値にできます。
PyType_HasFeature() マクロは型とフラグ値、
tp および f をとり、tp->tp_flags & f
が非ゼロかどうか調べます。
サブタイプはこのフィールドを継承しません。
以下の三つのフィールドは、Py_TPFLAGS_HAVE_RICHCOMPARE フラグビットがセットされている場合にのみ存在します。
tp_traverse ポインタは、ガベージコレクタが循環参照を見つけるために 使われます。 tp_traverse 関数の典型的な実装は、インスタンスの各メンバのうち Pythonオブジェクトに対して Py_VISIT() を呼び出します。 例えば、次のコードは thread 拡張モジュールの local_traverse 関数になります:
static int local_traverse(localobject *self, visitproc visit, void *arg) { Py_VISIT(self->args); Py_VISIT(self->kw); Py_VISIT(self->dict); return 0; }
Py_VISIT() が循環参照になる恐れのあるメンバにだけ呼び出されていることに 注目してください。 "self->key" メンバもありますが、それは NULL か Python文字列なので、 循環参照の一部になることはありません。
一方、メンバが循環参照の一部になり得ないと判っていても、デバッグ目的で巡回したい 場合があるかもしれないので、 gc モジュールの get_reference() 関数は 循環参照になり得ないメンバも返します。
Py_VISIT() は local_traverse が visit と arg という決まった名前の引数を持つことを要求します。
このフィールドは tp_clear および Py_TPFLAGS_HAVE_GC フラグビットと一緒に継承されます: フラグビット、tp_traverse、 および tp_clear の値がサブタイプで全てゼロになっており、 かつ サブタイプで Py_TPFLAGS_HAVE_RICHCOMPARE フラグビットがセットされている場合に、基底タイプから値を継承します。
tp_clear メンバ関数はGCが見つけた循環しているゴミの循環参照を 壊すために用いられます。 システム内の全ての tp_clear 関数によって、全ての循環参照を破壊しなければなりません。 (訳注: ある型がtp_clearを実装しなくても全ての循環参照が破壊できるのであれば 実装しなくても良い) これはとても繊細で、もし少しでも不確かな部分があるのであれば、tp_clear 関数を提供するべきです。 例えば、タプルはtp_clearを実装しません。なぜなら、 タプルだけで構成された循環参照がみつかることは無いからです。 したがって、タプル以外の型 tp_clear 関数たちが、タプルを含むどんな循環参照も 破壊できる必要があります。 これは簡単に判ることでははありません。 tp_clear の実装を避ける良い理由はめったにありません。
tp_clear の実装は、次の実装のように、インスタンスの (Pythonオブジェクト)メンバに対する参照を捨てて、メンバに対するポインタ変数を NULL にセットするべきです:
static int local_clear(localobject *self) { Py_CLEAR(self->key); Py_CLEAR(self->args); Py_CLEAR(self->kw); Py_CLEAR(self->dict); return 0; }
参照のクリアはデリケートなので、Py_CLEAR()マクロを使うべきです: ポインタをNULLにせっとするまで、そのオブジェクトの参照カウントを デクリメントしてはいけません。 参照カウントのデクリメントすると、そのオブジェクトが破棄されるかもしれず、 (そのオブジェクトに関連付けられたファイナライザ、弱参照のコールバックにより) 任意のPythonコードの実行を含む後片付け処理が実行されるかもしれないからです。 もしそういったコードが再び self を参照することがあれば、すでに 持っていたオブジェクトへのポインタは NULL になっているので、 self は所有していたオブジェクトをもう利用できないことを認識できます。 Py_CLEAR()マクロはその手続きを安全な順番で実行します。
tp_clear 関数の目的は参照カウントを破壊することなので、Python文字列や Python整数のような、循環参照になりえないオブジェクトをクリアする必要はありません。 一方、全部の所有オブジェクトをクリアするようにし、 tp_dealloc 関数が tp_clear 関数を実行するようにすると実相が楽です。
Pythonのガベージコレクションの仕組みについての詳細は、 10.9 にあります。
このフィールドは tp_traverse および Py_TPFLAGS_HAVE_GC フラグビットと一緒に継承されます: フラグビット、tp_traverse、 および tp_clear の値がサブタイプで全てゼロになっており、 かつ サブタイプで Py_TPFLAGS_HAVE_RICHCOMPARE フラグビットがセットされている場合に、基底タイプから値を継承します。
シグネチャはPyObject_RichCompare() と同じです。
この関数は、比較結果を返すべきです。(普通は Py_True
か Py_False
です。)
比較が未定義の場合は、 Py_NotImplemented
を、それ以外のエラーが
発生した場合には例外状態をセットして NULL
を返さねばなりません。
このフィールドはtp_compare およびtp_hash と共にサブタイプに継承されます: すなわち、サブタイプの tp_compare 、tp_richcompare および tp_hash が共に NULLの場合、サブタイプは 基底タイプからtp_compare、tp_richcompare、 tp_hash の三つを一緒に継承します。
tp_richcompare およびPyObject_RichCompare() 関数の第三引数に使うための定数としては以下が定義されています:
定数 | 比較 |
---|---|
Py_LT | < |
Py_LE | <= |
Py_EQ | == |
Py_NE | != |
Py_GT | > |
Py_GE | >= |
次のフィールドは、Py_TPFLAGS_HAVE_WEAKREFS フラグビットがセットされている場合にのみ存在します。
このフィールドを tp_weaklist と混同しないようにしてください; tp_weaklist は型オブジェクト自体の弱参照リストの先頭です。
サブタイプはこのフィールドを継承しますが、以下の規則があるので 読んでください。 サブタイプはこのオフセット値をオーバライドできます; 従って、 サブタイプでは弱参照リストの先頭が基底タイプとは異なる場合が あります。リストの先頭は常にtp_weaklistoffset で 分かるはずなので、このことは問題にはならないはずです。
class 文で定義された型に __slots__ 宣言が 全くなく、かつ基底タイプが弱参照可能でない場合、 その型を弱参照可能にするには弱参照リストの先頭を表すスロットを インスタンスデータレイアウト構造体に追加し、スロットのオフセットを tp_weaklistoffset に設定します。
型の __slots__ 宣言中に __weakref__ という名前の スロットが入っている場合、スロットはその型のインスタンスにおける 弱参照リストの先頭を表すスロットになり、スロットのオフセットが 型の tp_weaklistoffset に入ります。
型の __slots__ 宣言に __weakref__ という名のスロット が入っていない場合、その型は基底タイプからtp_weaklistoffset を継承します。
次の二つのフィールドは、Py_TPFLAGS_HAVE_CLASS フラグビットがセットされている場合にのみ存在します。
This function has the same signature as PyObject_GetIter().
サブタイプはこのフィールドを継承します。
イテレータ型では、 tp_iter 関数も定義していなければならず、 tp_iter は (新たなイテレータインスタンスではなく) イテレータインスタンス自体を返さねばなりません。
この関数のシグネチャは PyIter_Next() と同じです。
サブタイプはこのフィールドを継承します。
次の tp_weaklist までのフィールドは、 Py_TPFLAGS_HAVE_CLASS フラグビットがセットされている場合にのみ存在します。
配列の各要素ごとに、メソッドデスクリプタの入ったエントリが 型辞書 (下記の tp_dict 参照) に追加されます。
サブタイプはこのフィールドを継承しません (メソッドは別個の メカニズムで継承されています)。
配列の各要素ごとに、メンバデスクリプタの入ったエントリが 型辞書 (下記の tp_dict 参照) に追加されます。
サブタイプはこのフィールドを継承しません (メンバは別個の メカニズムで継承されています)。
配列の各要素ごとに、getset デスクリプタの入ったエントリが 型辞書 (下記の tp_dict 参照) に追加されます。
サブタイプはこのフィールドを継承しません (算出属性は別個の メカニズムで継承されています)。
Docs for PyGetSetDef (XXX belong elsewhere):
typedef PyObject *(*getter)(PyObject *, void *); typedef int (*setter)(PyObject *, PyObject *, void *); typedef struct PyGetSetDef { char *name; /* 属性名 */ getter get; /* 属性の get を行う C 関数 */ setter set; /* 属性の set を行う C 関数 */ char *doc; /* オプションの docstring */ void *closure; /* オプションの get/set 関数用追加データ */ } PyGetSetDef;
(当たり前ですが) サブタイプはこのフィールドを継承しません。しかし、
このフィールドのデフォルト値は
(Python プログラマはobject 型として知っている)
&PyBaseObject_Type
になります。
.
このフィールドは通常、PyType_Ready() を呼び出す前に NULL に初期化しておかねばなりません; あるいは、型の初期属性の入った 辞書で初期化しておいてもかまいません。PyType_Ready() が 型をひとたび初期化すると、型の新たな属性をこの辞書に追加できるのは、 属性が (__add__() のような) オーバロード用演算でないとき だけです。
サブタイプはこのフィールドを継承しません (が、この辞書内で 定義されている属性は異なるメカニズムで継承されます)。
関数のシグネチャは次のとおりです。
PyObject * tp_descr_get(PyObject *self, PyObject *obj, PyObject *type);
XXX blah, blah.
サブタイプはこのフィールドを継承します。
関数のシグネチャは次のとおりです。
int tp_descr_set(PyObject *self, PyObject *obj, PyObject *value);
サブタイプはこのフィールドを継承します。
XXX blah, blah.
このフィールドを tp_dict と混同しないでください; tp_dict は型オブジェクト自体の属性のための辞書です。
このフィールドの値がゼロより大きければ、値はインスタンス構造体の
先頭からのオフセットを表します。値がゼロより小さければ、
インスタンス構造体の 末尾 からのオフセットを表します。
負のオフセットを使うコストは比較的高くつくので、インスタンス構造体に
可変長の部分があるときのみ使うべきです。
例えば、str や tuple のサブタイプにインスタンス
辞書を追加する場合には、負のオフセットを使います。
この場合、たとえ辞書が基本のオブジェクトレイアウトに含まれていなくても、
tp_basicsize フィールドは追加された辞書を考慮にいれなければ
ならないので注意してください。ポインタサイズが 4 バイトのシステムでは、
構造体の最後尾に辞書が宣言されていることを示す場合、
tp_dictoffset を-4
にしなければなりません。
tp_dictoffset が負の場合、インスタンスにおける実際の辞書の オフセットは以下のようにして計算されます:
dictoffset = tp_basicsize + abs(ob_size)*tp_itemsize + tp_dictoffset if dictoffset is not aligned on sizeof(void*): round up to sizeof(void*)
ここで、tp_basicsize、 tp_itemsize および tp_dictoffset は型オブジェクトから取り出され、 ob_size はインスタンスから取り出されます。 長整数は符号を記憶するのに ob_size の符号を使うため、 ob_size は絶対値を使います。(この計算を自分で行う必要は まったくありません; _PyObject_GetDictPtr() が やってくれます。)
サブタイプはこのフィールドを継承しますが、以下の規則があるので 読んでください。 サブタイプはこのオフセット値をオーバライドできます; 従って、 サブタイプでは辞書のオフセットが基底タイプとは異なる場合が あります。辞書へのオフセット常にtp_dictoffset で 分かるはずなので、このことは問題にはならないはずです。
class 文で定義された型に __slots__ 宣言が 全くなく、かつ基底タイプの全てにインスタンス変数辞書がない場合、 辞書のスロットをインスタンスデータレイアウト構造体に追加し、 スロットのオフセットをtp_dictoffset に設定します。
class 文で定義された型に __slots__ 宣言が ある場合、この型は基底タイプから tp_dictoffset を 継承します。
(__dict__ という名前のスロットを __slots__ 宣言に 追加しても、期待どおりの効果は得られず、単に混乱を招くだけに なります。とはいえ、これは将来__weakref__ のように 追加されるはずです。)
この関数はクラスにおける __init__() メソッドに対応 します。__init__() と同様、__init__() を呼び出さず にインスタンスを作成できます。また、__init__() を再度 呼び出してインスタンスの再初期化もできます。
関数のシグネチャは
int tp_init(PyObject *self, PyObject *args, PyObject *kwds)
です。
self 引数は初期化するインスタンスです; args および kwds 引数は、__init__() を呼び出す際の 固定引数およびキーワード引数です。
tp_init 関数のフィールドが NULLでない場合、型の呼び出し で普通にインスタンスを生成する際に、型のtp_new が インスタンスを返した後にtp_init が呼び出されます。 tp_new が元の型のサブタイプでない別の型を返す場合、 tp_init は全く呼び出されません; tp_new が 元の型のサブタイプのインスタンスを返す場合、サブタイプの tp_init が呼び出されます。 (VERSION NOTE: ここに書かれている 内容は、Python 2.2.1 以降での実装に関するものです。Python 2.2 では、 tp_init は NULLでない限りtp_new が返す全ての オブジェクトに対して常に呼び出されます。) not NULL.)
サブタイプはこのフィールドを継承します。
関数のシグネチャは
PyObject *tp_alloc(PyTypeObject *self, Py_ssize_t nitems)
です。
この関数の目的は、メモリ確保をメモリ初期化から分離することにあります。
この関数は、インスタンス用の的確なサイズを持ち、適切にバイト整列
され、ゼロで初期化され、ただしob_refcnt を 1
にセットされ、 ob_type が型引数 (type argument) にセットされて
いるようなメモリブロックを返さねばなりません。
型の tp_itemsize がゼロでない場合、オブジェクトの
ob_size フィールドはnitems に初期化され、
確保されるメモリブロックの長さは tp_basicsize +
nitems*tp_itemsize
をsizeof(void*)
の倍数で
丸めた値になるはずです; それ以外の場合、nitems の値は使われず、
メモリブロックの長さは tp_basicsize になるはずです。
この関数をインスタンス初期化の他のどの処理にも、追加でメモリ確保 をする場合でさえ使ってはなりません; そうした処理は tp_new で行わねばなりません。
静的なサブタイプはこのフィールドを継承しますが、動的なサブタイプ (class 文で生成するサブタイプ) の場合は継承しません; 後者の場合、このフィールドは常にPyType_GenericAlloc() にセットされ、標準のヒープ上メモリ確保戦略が強制されます。 静的に定義する型の場合でも、PyType_GenericAlloc() を推奨します。
このフィールドが NULL を指している型では、型を呼び出して新たな インスタンスを生成できません; こうした型では、おそらくファクトリ 関数のように、インスタンスを生成する他の方法があるはずです。
関数のシグネチャは
PyObject *tp_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
です。
引数 subtype は生成するオブジェクトの型です; args およびkwds 引数は、型を呼び出すときの 固定引数およびキーワード引数です。サブタイプは tp_new 関数 を呼び出すときに使う型と等価というわけではないので注意してください; tp_new 関数を呼び出すときに使う型 (と無関係ではない) サブタイプのこともあります。
tp_new 関数は
subtype->tp_alloc(subtype, nitems)
を呼び出してオブジェクトのメモリ領域を確保し、初期化で本当に必要と
される処理だけを行います。省略したり繰り返したりしても問題のない
初期化処理はtp_init ハンドラ内に配置しなければなりません。
経験則からいうと、変更不能な型の場合、初期化は全て tp_new
で行い、変更可能な型の場合はほとんどの初期化を
tp_init に回すべきです。
サブタイプはこのフィールドを継承します。例外として、 tp_base
がNULL か&PyBaseObject_Type
になっている静的な型では
継承しません。後者が例外になっているのは、旧式の拡張型が Python 2.2
でリンクされたときに呼び出し可能オブジェクトにならないように
するための予防措置です。
この関数のシグネチャは少し変更されています; Python 2.2 および 2.2.1 では、シグネチャはdestructor :
void tp_free(PyObject *)
でしたが、 Python 2.3 以降では、シグネチャは freefunc:
void tp_free(void *)
になっています。
両方のバージョンと互換性のある初期値は _PyObject_Del
です。 _PyObject_Del
の定義は Python 2.3 で適切に対応できる
よう変更されました。
静的なサブタイプはこのフィールドを継承しますが、動的なサブタイプ (class 文で生成するサブタイプ) の場合は継承しません; 後者の場合、このフィールドにはPyType_GenericAlloc() とPy_TPFLAGS_HAVE_GC フラグビットの値に対応させるのに ふさわしいメモリ解放関数がセットされます。
ガベージコレクタは、オブジェクトがガベージとして収集可能かどうか
を知る必要があります。これを知るには、通常はオブジェクトの型の
tp_flags フィールドを見て、 Py_TPFLAGS_HAVE_GC
フラグビットを調べるだけで十分です。しかし、静的なメモリ確保と
動的なメモリ確保が混じっているインスタンスを持つような型や、
静的にメモリ確保されたインスタンスは収集できません。こうした型では、
このフィールドに関数を定義しなければなりません; 関数は
インスタンスが収集可能の場合には 1
を、
収集不能の場合には 0
を返さねばなりません。
シグネチャは
int tp_is_gc(PyObject *self)
です。
(上記のような型の例は、型オブジェクト自体です。メタタイプ PyType_Type は、型のメモリ確保が静的か動的かを 区別するためにこの関数を定義しています。)
サブタイプはこのフィールドを継承します。 (VERSION NOTE: Python 2.2 では、このフィールドは継承されませんでした。 2.2.1 以降のバージョンから継承されるようになりました。)
class 文で生成されたクラスの場合このフィールドがセット されます。静的に定義されている型の場合には、このフィールドは NULL になります。
このフィールドは継承されません。
このフィールドは継承されません; フィールドの値は PyType_Ready() で毎回計算されます。
残りのフィールドは、機能テスト用のマクロである COUNT_ALLOCS が定義されている場合のみ利用でき、内部で使用するためだけのものです。 これらのフィールドについて記述するのは単に完全性のためです。 サブタイプはこれらのフィールドを継承しません。
また、 Python のガベージコレクションでは、tp_dealloc を呼び出すのはオブジェクトを生成したスレッドだけではなく、 任意の Python スレッドかもしれないという点にも注意して下さい。 (オブジェクトが循環参照の一部の場合、任意のスレッドのガベージコレクション によって解放されてしまうかもしれません)。Python API 側からみれば、 tp_dealloc を呼び出すスレッドは グローバルインタプリタロック (GIL: Global Interpreter Lock) を獲得するので、これは問題ではありません。 しかしながら、削除されようとしているオブジェクトが何らかの C や C++ ライブラリ由来のオブジェクトを削除する場合、 tp_dealloc を 呼び出すスレッドのオブジェクトを削除することで、ライブラリの仮定 している何らかの規約に違反しないように気を付ける必要があります。
ご意見やご指摘をお寄せになりたい方は、 このドキュメントについて... をご覧ください。