私はいくつかの Python ユーティリティ関数を追加したい C 拡張モジュールを持っています。これを行うための推奨される方法はありますか?
例えば:
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 を含む) で純粋な Python (または他の言語) の実装を許可するという潜在的な利点があります。
ただし、場合によっては、C よりも Python でより適切に記述されたいくつかのエクストラを提供するためだけに、モジュールを C レイヤーと Python レイヤーに分割する価値がない場合があります。たとえば、gmpy (この 7113 行目以降) time) の型のインスタンスの酸洗を有効にするために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
(または他の方法で)構築されたものとして使用PyModule_GetDict
し、一時的な辞書ではなく、する名前空間PyRun_String
。PyRun_String
もちろん、必要なdef
andステートメントよりも洗練されたアプローチもclass
ありますが、単純なケースでは、この単純なアプローチで十分な場合があります。