拡張型の特殊メソッド

このページでは、現在 Cython の拡張型がサポートしている特殊メソッドにつ いて解説します。全特殊メソッドの一覧が末尾のテーブルにあります。 特殊メソッドの中には、 Python 側で対応する特殊メソッドの存在しないもの もあり、特に注意が必要です。

特殊メソッドの宣言

特殊メソッドは必ず def で宣言します。 cdef では 宣言できません。ただし、パフォーマンスには影響しません–Pythonは特殊メ ソッドを特別なやり方で呼び出すからです。

ドキュメンテーション文字列

Cython は拡張型の特殊メソッドの docstring をまだ完全サポートしていませ ん。ソースコードにはコメントとして docstring を書けますが、その内容を 実行時に:attr:__doc__ アトリビュートで見られません。(これは Python の制約と考えられます – PyTypeObject データ型には、 docstring を入 れる場所がないのです)

初期化メソッド: __cinit__()__init__()

拡張型の初期化時には、二つの特殊メソッドが関係します。

__cinit__() メソッドは、は、 C データ構造のアロケーションを含み、 オブジェクトを C レベルで初期化するための処理を書く場所です。 __cinit__() メソッドで何かする場合には、注意深くなければなりませ ん。というのも、メソッドが呼び出された段階では、オブジェクトはまだ Python オブジェクトとして完全に有効な状態ではないことがあるからです。 そのため、このオブジェクトに触れるような Python の操作、とりわけオブジェ クトのメソッドを呼び出すときには、特に注意が必要です。

__cinit__() メソッドを呼び出す前に、オブジェクトのオブジェクトの メモリ領域はアロケーションを完了しています。また、 C レベルのアトリビュー トの値は、全て 0 か NULL に初期化されています (Python オブジェクトの入 るアトリビュートは None に初期化されていますが、それをあてにすべき ではありません)。 __cinit__() メソッド必ず一度だけ呼び出されるこ とが保証されています。

何らかの基底型を継承している拡張型の場合、基底型の __cinit__() が自動的に呼び出されてから、拡張型の __cinit__() が呼ばれます。 基底型から継承した __cinit__() は明示的に呼び出せません。 引数リストを変更してから基底クラスに渡したい場合は、同じようなことを (継承したメソッドの扱いについて、通常の Python の規則が適用される) __init__() メソッドの中で行う必要があるでしょう。

__cinit__() メソッドの中で安全に行えない操作は、全て __init__() メソッド中で行わねばなりません。 __init__() を 呼び出す段階では、オブジェクトは Python オブジェクトとして完全に有効な 状態になっており、どんな操作も安全に実行できます。また、状況によっては、 __init__() は複数回呼び出されることもあれば、全く呼び出されない こともありえます。他のメソッドは、 __init__() が呼ばれても呼ば れなくても影響を受けないような設計にしましょう。

コンストラクタに渡した引数は、 __cinit__() メソッドと __init__() メソッドの両方に渡されます。拡張型を Python でサブク ラス化しようと思っているなら、 __cinit__() メソッドに *** といった引数を用意しておくと、余分な引数を受け取ったり、無視した りさせられるので便利だと判るでしょう。さもないと、 Python のサブクラス 側で __init__() メソッドのシグネチャが異なるときに、 を変えたいときに、 __new__() [#] と __init__() メソッドの 両方をオーバライドするという、余計な作業をせねばなりません。 簡単のために、 __cinit__() が (self 以外の) 引数を持たないよ うに宣言すると、コンストラクタにいくつ引数を渡しても全て無視し、シグネ チャの不一致が起きても文句を言わなくなります。

[1]http://docs.python.org/reference/datamodel.html#object.__new__

後始末メソッド: __dealloc__()

__dealloc__() は、 __cinit__() の対極に位置するメソッドで す。このメソッドでは __cinit__() と逆の処理を行わねばなりません。 __cinit__() で (malloc などで) 明示的にアロケートした C のデータ 領域は、 __dealloc__() メソッドで free せねばなりません。

__dealloc__() で何か操作を行う場合は、注意深くなければなりません。 __dealloc__() メソッドが呼び出された時点で、オブジェクトはすでに 部分的に破壊されており、 Python のオブジェクトとしては有効な状態にない ことがあります。そのため、オブジェクトを触るような Python の操作は一切 呼ばないようにしましょう。とりわけ、決してオブジェクトの他のメソッドは 呼び出してはなりません。さもないと、削除するはずのオブジェクトを蘇生さ せてしまいます。単に C のデータ構造のためにアロケートした領域の開放だ けにするのがベストです。

Python オブジェクトのアトリビュートのデアロケートは、 __dealloc__() メソッドが処理を戻した後に、 Cython によって開放さ れるので、気にする必要はありません。

算術メソッド

__add__() のような算術メソッドの振る舞いは、対応する Python のメ ソッドと異っています。拡張型の算術メソッドには、「逆向き」バージョン、 (__radd__() など) はありません。その代わり、最初の被演算子が目的 の演算を実行できなければ、ふたつめの被演算子の算術メソッドが、被演算子 の順番を同じにして呼び出されます。

そのため、算術メソッドでは、メソッドの最初のパラメタが “self” であった り、適切なデータ型であると期待してはなりません。必ず、処理を行う前に、 被演算子の両方に対して型を調べて下さい。扱えないデータ型や、適合しない データ型の場合には NotImplemented を返さねばなりません。

この挙動は、インプレース演算メソッド __ipow__() にも当てはまります。 その他の、(__iadd__() のような) インプレース演算メソッドには当て はまらず、常に self を第一引数として受け取ります。

リッチな比較

各々のリッチ比較演算のための、固有の特殊メソッド (__eq__()__le__() など) はありません。その代わり、全てのリッチ比較に対し て、 __richcmp__() が呼び出されます。 __richcmp__() は、ど のような演算を実行するかを表す整数の引数をとります。引数の意味は下記の 表の通りです:

< 0
== 2
> 4
<= 1
!= 3
>= 5

特殊メソッド一覧

以下のテーブルには、全ての特殊メソッドと、パラメタ、戻り値の型をまとめ ています。このテーブルでは、 self という名前のパラメタは、メソッドを呼 び出した対象のオブジェクトの型であることを示します。その他のパラメタは、 型の指定がない場合、一般の Python オブジェクトを指します。

特殊メソッドを定義するときに、これらのパラメタ型を取るよう宣言する必要 はありません。異なる型を定義すると、必要に応じて変換が行われます。

汎用特殊メソッド

名前 パラメタ 戻り値型 説明
__cinit__ self, ...   基本の初期化 (Python の対応するメソッドなし)
__init__ self, ...   追加の初期化
__dealloc__ self   基本のでアロケーション (直接対応するメソッドなし)
__cmp__ x, y int 3 値比較演算子
__richcmp__ x, y, int op object リッチ比較 (直接対応するPython のメソッドなし)
__str__ self object str(self)
__repr__ self object repr(self)
__hash__ self int ハッシュ関数
__call__ self, ... object self(...)
__iter__ self object シーケンスのイテレータを返す
__getattr__ self, name object アトリビュートを取得する
__getattribute__ self, name object 無条件でアトリビュートを取得する
__setattr__ self, name, val   アトリビュートをセットする
__delattr__ self, name   アトリビュートを削除する

算術演算子

名前 パラメタ 戻り値型 説明
__add__ x, y object 二項演算子 +
__sub__ x, y object 二項演算子 -
__mul__ x, y object 演算子 *
__div__ x, y object 古いスタイルの除算演算子 /
__floordiv__ x, y object 演算子 //
__truediv__ x, y object 新しいスタイルの除算演算子 /
__mod__ x, y object 演算子 %
__divmod__ x, y object div と mod の合併演算子
__pow__ x, y, z object ** 演算子、または pow(x, y, z)
__neg__ self object 単項演算子 -
__pos__ self object 単項演算子 +
__abs__ self object 絶対値
__nonzero__ self int ブール値への変換
__invert__ self object 演算子 ~
__lshift__ x, y object 演算子 <<
__rshift__ x, y object 演算子 >>
__and__ x, y object 演算子 &
__or__ x, y object 演算子 |
__xor__ x, y object 演算子 ^

数値型変換

名前 パラメタ 戻り値型 説明
__int__ self object integer への変換
__long__ self object long integer への変換
__float__ self object float への変換
__oct__ self object 8進表現への変換
__hex__ self object 16進表現への変換
__index__ (2.5+ のみ) self object シーケンスインデクスへの変換

インプレース算術演算子

名前 パラメタ 戻り値型 説明
__iadd__ self, x object 演算子 +=
__isub__ self, x object 演算子 -=
__imul__ self, x object 演算子 *=
__idiv__ self, x object 古いスタイルの除算演算子 /=
__ifloordiv__ self, x object 演算子 //=
__itruediv__ self, x object 新しいスタイルの除算演算子 /=
__imod__ self, x object 演算子 %=
__ipow__ x, y, z object 演算子 **=
__ilshift__ self, x object 演算子 <<=
__irshift__ self, x object 演算子 >>=
__iand__ self, x object 演算子 &=
__ior__ self, x object 演算子 |=
__ixor__ self, x object 演算子 ^=

シーケンス・マップ型関連

名前 パラメタ 戻り値型 説明
__len__ self int len(self)
__getitem__ self, x object self[x]
__setitem__ self, x, y   self[x] = y
__delitem__ self, x   del self[x]
__getslice__ self, Py_ssize_t i, Py_ssize_t j object self[i:j]
__setslice__ self, Py_ssize_t i, Py_ssize_t j, x   self[i:j] = x
__delslice__ self, Py_ssize_t i, Py_ssize_t j   del self[i:j]
__contains__ self, x int x in self

イテレータ関連

名前 パラメタ 戻り値型 説明
__next__ self object 次の要素を取り出す (Python で next が呼ばれた

バッファインタフェース [PEP 3118] (Python の対応するメソッドなし - 注 1 参照)

名前 パラメタ 戻り値型 説明
__getbuffer__ self, Py_buffer *view, int flags    
__releasebuffer__ self, Py_buffer *view    

バッファインタフェース [旧] (Python の対応するメソッドなし - 注 1 参照)

名前 パラメタ 戻り値型 説明
__getreadbuffer__ self, Py_ssize_t i, void **p    
__getwritebuffer__ self, Py_ssize_t i, void **p    
__getsegcount__ self, Py_ssize_t *p    
__getcharbuffer__ self, Py_ssize_t i, char **p    

デスクリプタオブジェクト (注 2 参照)

名前 パラメタ 戻り値型 説明
__get__ self, instance, class object アトリビュートの値を取得する
__set__ self, instance, value   アトリビュートの値をセットする
__delete__ self, instance   アトリビュートを削除する

Note

(1) バッファインタフェースは C のコードから使うためのもので、 Python からは直接アクセスできません。バッファインタフェースの 解説は、Python 2.x の Python/C API リファレンス・マニュアル 6.6 節と 10.6 節にあります。Python 2.6 以降、古いバッファイン タフェースは PEP 3118 の新しいバッファプロトコルに置き換わり、 Python 3 では使えなくなりました。

Note

(2) デスクリプタオブジェクトは、新しいスタイルの Python のク ラスをサポートするメカニズムの一部です。デスクリプタに関する議 論は、Python のドキュメントを参照してください。また、 PEP 252, “Making Types Look More Like Classes” と、 PEP 253, “Subtyping Built-In Types” も参照してください。