質問
C拡張モジュールがあります。これにPythonユーティリティ関数をいくつか追加します。これを行うための推奨される方法はありますか?
例:
import my_module
my_module.super_fast_written_in_C()
my_module.written_in_Python__easy_to_maintain()
主にPython 2.xに興味があります。
解決
これを行う通常の方法は、mymod.pyにPythonで記述されたユーティリティ関数が含まれ、Cで記述され_mymod.soまたは_mymod.pydからインポートされた_mymodモジュールにグッズをインポートします。たとえば、Pythonディストリビューションの... / Lib / csv.pyを見てください。
他のヒント
ネイティブ拡張の前にアンダースコアを付けます。 次に、Pythonで、そのネイティブ拡張をインポートし、その上に他の非ネイティブルーチンを追加するラッパーモジュールを作成します。
既存の回答は、最も頻繁に使用される方法を説明しています:コンパイルされたC拡張が利用できないプラットフォーム(JythonおよびIronPythonを含む)でpure-Python(または他の言語)実装を許可する潜在的な利点があります。
ただし、いくつかのケースでは、モジュールをCレイヤーとPythonレイヤーに分割して、CよりもPythonで賢明に記述された追加機能を提供するだけの価値がない場合があります。たとえば、 gmpy (現時点では7113行目以降)、順番に gmpy
のタイプのインスタンスのピクルを有効にするには、次を使用します:
copy_reg_module = PyImport_ImportModule("copy_reg");
if (copy_reg_module) {
char* enable_pickle =
"def mpz_reducer(an_mpz): return (gmpy.mpz, (an_mpz.binary(), 256))\n"
"def mpq_reducer(an_mpq): return (gmpy.mpq, (an_mpq.binary(), 256))\n"
"def mpf_reducer(an_mpf): return (gmpy.mpf, (an_mpf.binary(), 0, 256))\n"
"copy_reg.pickle(type(gmpy.mpz(0)), mpz_reducer)\n"
"copy_reg.pickle(type(gmpy.mpq(0)), mpq_reducer)\n"
"copy_reg.pickle(type(gmpy.mpf(0)), mpf_reducer)\n"
;
PyObject* namespace = PyDict_New();
PyObject* result = NULL;
if (options.debug)
fprintf(stderr, "gmpy_module imported copy_reg OK\n");
PyDict_SetItemString(namespace, "copy_reg", copy_reg_module);
PyDict_SetItemString(namespace, "gmpy", gmpy_module);
PyDict_SetItemString(namespace, "type", (PyObject*)&PyType_Type);
result = PyRun_String(enable_pickle, Py_file_input,
namespace, namespace);
これらのいくつかの追加機能を「動かない」ようにしたい場合モジュールでは(この例では必要ありません)、もちろん Py_InitModule3
(またはその他のメソッド)によって構築されたモジュールオブジェクトと、 PyRun_String
の名前空間としての一時的な辞書。そしてもちろん、必要な def
および class
ステートメントを PyRun_String
よりも洗練されたアプローチがありますが、単純なケースでは、この単純なアプローチ実際には十分かもしれません。