pytho****@googl*****
pytho****@googl*****
2011年 11月 11日 (金) 01:05:56 JST
Revision: 9577393987b4 Author: Naoki INADA <inada****@klab*****> Date: Thu Nov 10 08:04:53 2011 Log: Update 2.7.2: extending/extending http://code.google.com/p/python-doc-ja/source/detail?r=9577393987b4 Modified: /extending/extending.rst ======================================= --- /extending/extending.rst Wed Aug 24 03:05:50 2011 +++ /extending/extending.rst Thu Nov 10 08:04:53 2011 @@ -73,9 +73,8 @@ ここでは、Python の引数リスト (例えば、単一の式 ``"ls -l"``) から C 関数に 渡す引数にそのまま変換しています。 C 関数は常に二つの引数を持ち、便宜的に *self* および *args* と呼ばれます。 -*self* 引数は C 関数が Python の関数ではなく組み込みメソッドを実装している 場合にのみ使われます。この例ではメソッドではなく -関数を定義しているので、 *self* は常に *NULL* ポインタになります。 (これ は、インタプリタが二つの異なる形式の C 関数を理解しなくてもよく -するためです。) +*self* 引数には、モジュールレベルの関数であればモジュールが、メソッドには +オブジェクトインスタンスが渡されます。 *args* 引数は、引数の入った Python タプルオブジェクトへのポインタになりま す。タプル内の各要素は、呼び出しの際の引数リストに おける各引数に対応します。引数は Python オブジェクトです --- C 関数で引数 を使って何かを行うには、オブジェクトから C の値に @@ -323,11 +322,7 @@ :file:`.so` 、Windows では :file:`.dll`) から読み出された場合にはモジ ュールファイルを再読み込みしないので注意してください。 より実質的なモジュール例は、Python ソース配布物 に :file:`Modules/xxmodule.c` という名前で入っています。 -このファイルはテンプレートとしても利用できますし、単に例としても読めます。 ソース配布物や Windows にインストールされた Python に入っている -:program:`modulator.py` では、拡張モジュールで実装しなければならない -関数やオブジェクトを宣言し、実装部分を埋めて作成するためのテンプレートを生 成できるような、簡単なグラフィカルユーザインタフェースを提供しています。 -このスクリプトは :file:`Tools/modulator/` ディレクトリにあります; 詳しくは ディレクトリ内の :file:`README` -ファイルを参照してください。 +このファイルはテンプレートとしても利用できますし、単に例としても読めます。 .. _compilation: @@ -915,7 +910,7 @@ {...}`` が行われるように、ヘッダファイル内にすでに書かれているからです。 -.. _using-cobjects: +.. _using-capsules: 拡張モジュールに C API を提供する ================================= @@ -940,18 +935,36 @@ と宣言せねばなりません。例外はモジュールの初期化関数で、これは (:ref:`methodtable` で述べたように) 他の拡張モジュールとの間で 名前が衝突するのを避けるためです。また、他の拡張モジュールからアクセスを *受けるべきではない* シンボルは別のやり方で公開せねばなりません。 -Python はある拡張モジュールの C レベルの情報 (ポインタ) を別のモジュールに 渡すための特殊な機構: CObject を提供しています。 -CObject はポインタ (:c:type:`void\*`) を記憶する Python のデータ型です。 CObject は C API -を介してのみ生成したりアクセスしたりできますが、他の Python オブジェクトと 同じように受け渡しできます。とりわけ、CObject -は拡張モジュールの名前空間内にある名前に代入できます。他の拡張モジュールは このモジュールを import でき、次に名前を取得し、最後にCObject +Python はある拡張モジュールの C レベルの情報 (ポインタ) を別のモジュールに 渡すための +特殊な機構: Capsule (カプセル)を提供しています。 +Capsule はポインタ (:c:type:`void\*`) を記憶する Python のデータ型です。 Capsule は C API +を介してのみ生成したりアクセスしたりできますが、他の Python オブジェクトと 同じように受け渡しできます。 +とりわけ、Capsule は拡張モジュールの名前空間内にある名前に代入できます。 +他の拡張モジュールはこのモジュールを import でき、次に名前を取得し、最後に Capsule へのポインタを取得します。 -拡張モジュールの C API を公開するために、様々な方法で CObject が使われま す。エクスポートされているそれぞれの名前を使うと、CObject -自体や、CObject が公表しているアドレスで示される配列内に収められた全ての C API ポインタを得られます。 -そして、ポインタに対する保存や取得といった様々な作業は、コードを提供してい るモジュールとクライアントモジュールとの間では異なる方法で分散できます。 +拡張モジュールの C API を公開するために、様々な方法で Capsule が使われま す。 +各関数を1つのオブジェクトに入れたり、全ての C API のポインタ配列を Capsule に入れることができます。 +そして、ポインタに対する保存や取得といった様々な作業は、コードを提供してい る +モジュールとクライアントモジュールとの間では異なる方法で分散できます。 + +どの方法を選ぶにしても、 Capsule の name を正しく設定することは重要です。 +:c:func:`PyCapsule_New` は name 引数 (:c:type:`const char \*`) を取ります。 +*NULL* を name に渡すことも許可されていますが、 name を設定することを強く推 奨します。 +正しく名前を付けられた Capsule はある程度の実行時型安全性を持ちます。 +名前を付けられていない Capsule を他の Capsule と区別する現実的な方法はあり ません。 + +特に、 C API を公開するための Capsule には次のルールに従った名前を付けるべ きです:: + + modulename.attributename + +:c:func:`PyCapsule_Import` という便利関数は、 Capsule の名前がこのルールに 一致しているときにのみ、 +簡単に Capsule 経由で公開されている C API をロードすることができます。 +この挙動により、 C API のユーザーが、確実に正しい C API を格納している Capsule を +ロードできたことを確かめることができます。 以下の例では、名前を公開するモジュールの作者にほとんどの負荷が掛かります が、よく使われるライブラリを作る際に適切なアプローチを実演します。 -このアプローチでは、全ての C API ポインタ (例中では一つだけですが!) を、 CObject の値となる :c:type:`void` +このアプローチでは、全ての C API ポインタ (例中では一つだけですが!) を、 Capsule の値となる :c:type:`void` ポインタの配列に保存します。拡張モジュールに対応するヘッダファイルは、モジ ュールの import と C API ポインタを取得するよう手配するマクロを提供します; クライアントモジュール は、C API にアクセスする前にこのマクロを呼ぶだけです。 @@ -1011,8 +1024,8 @@ /* C API ポインタ配列を初期化する */ PySpam_API[PySpam_System_NUM] = (void *)PySpam_System; - /* API ポインタ配列のアドレスが入った CObject を生成する */ - c_api_object = PyCObject_FromVoidPtr((void *)PySpam_API, NULL); + /* API ポインタ配列のアドレスが入った Capsule を生成する */ + c_api_object = PyCapsule_New((void *)PySpam_API, "spam._C_API", NULL); if (c_api_object != NULL) PyModule_AddObject(m, "_C_API", c_api_object); @@ -1053,28 +1066,14 @@ #define PySpam_System \ (*(PySpam_System_RETURN (*)PySpam_System_PROTO) PySpam_API[PySpam_System_NUM]) - /* エラーによる例外の場合には -1 を、成功すると 0 を返す */ + /* エラーによる例外の場合には -1 を、成功すると 0 を返す + * エラーがあれば PyCapsule_Import が例外を設定する。 + */ static int import_spam(void) { - PyObject *c_api_object; - PyObject *module; - - module = PyImport_ImportModule("spam"); - if (module == NULL) - return -1; - - c_api_object = PyObject_GetAttrString(module, "_C_API"); - if (c_api_object == NULL) { - Py_DECREF(module); - return -1; - } - if (PyCObject_Check(c_api_object)) - PySpam_API = (void **)PyCObject_AsVoidPtr(c_api_object); - - Py_DECREF(c_api_object); - Py_DECREF(module); - return 0; + PySpam_API = (void **)PyCapsule_Import("spam._C_API", 0); + return (PySpam_API != NULL) ? 0 : -1; } #endif @@ -1104,10 +1103,10 @@ このアプローチの主要な欠点は、 :file:`spammodule.h` がやや難解になるという ことです。とはいえ、各関数の基本的な構成は公開される ものと同じなので、書き方を一度だけ学べばすみます。 -最後に、CObject は、自身に保存されているポインタをメモリ確保したり解放した りする際に特に便利な、もう一つの機能を提供しているという +最後に、Capsule は、自身に保存されているポインタをメモリ確保したり解放した りする際に特に便利な、もう一つの機能を提供しているという ことに触れておかねばなりません。詳細は Python/C API リファレンスマニュアル の -:ref:`cobjects` 、および CObjects の実装部分 (Python -ソースコード配布物中のファイル :file:`Include/cobject.h` およ び :file:`Objects/cobject.c` +:ref:`capsules`, および Capsule の実装部分 (Python +ソースコード配布物中のファイル :file:`Include/pycapsule.h` およ び :file:`Objects/pycapsule.c` に述べられています。 .. rubric:: 脚注