そこで、C から Cython 経由で Python コードを呼び出したいのですが、C から Cython コードを呼び出すことはできました。また、Cython から Python コードを呼び出すこともできます。しかし、すべてを合計すると、いくつかが欠けています。
これが私の Python コードです ( quacker.pyx
)。
def quack():
print "Quack!"
これが私の Cython「ブリッジ」(caller.pyx
)です。
from quacker import quack
cdef public void call_quack():
quack()
そして、これが C コードです ( main.c
)。
#include <Python.h>
#include "caller.h"
int main() {
Py_Initialize();
initcaller();
call_quack();
Py_Finalize();
return 0;
}
これを実行すると、次の例外が発生します:
Exception NameError: "name 'quack' is not defined" in 'caller.call_quack' ignored
私が疑っている欠けている部分:
- 電話していない
initquacker()
- 含めていない
quacker.h
- Cythonは何も生産しなかった
quacker.h
-only quacker.c
caller.c
インポートquacker.h
も呼び出しも行いませんinitquacker()
私がやろうとしていることが本当に可能かどうかはわかりませんが、できるはずだと思っています。何かご意見があればぜひお聞かせください。
編集:
cython 化 / コンパイル / リンク / 実行の方法は、次のとおりです。
$ cython *.pyx
$ cc -c *.c -I/System/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7
$ cc -L/System/Library/Frameworks/Python.framework/Versions/2.7/lib -L/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/config -lpython2.7 -ldl *.o -o main
$ ./main
ベストアンサー1
quacker.pyx
を に名前変更するとquacker.py
、実際にはすべて正しくなります。唯一の問題は、プログラムが現在のディレクトリで Python モジュールを検索しないため、次のような出力になることです。
Exception NameError: "name 'quack' is not defined" in 'caller.call_quack' ignored
ただし、現在のディレクトリを PYTHONPATH 環境変数に追加すると、出力は期待どおりのものになります。
$ PYTHONPATH=".:$PYTHONPATH" ./main
Quack!
Pythonシェルを実行すると、ドキュメンテーション現在のディレクトリ (またはスクリプトを含むディレクトリ) はsys.path
自動的に変数に追加されますが、を使用して簡単なプログラムを作成するとPy_Initialize
、Py_Finalize
これは行われないようです。 PYTHONPATH 変数はsys.path
Python 変数を設定するためにも使用されるため、上記の回避策により正しい結果が得られます。
あるいは、文字列として指定された Python コードを実行するだけでPy_Intialize
、次の行の下に空の文字列を追加することもできます。sys.path
PyRun_SimpleString("import sys\nsys.path.insert(0,'')");
再コンパイル後、実行するだけ./main
で動作するはずです。
編集
質問で指定されているとおりに、つまりファイル名を変更せずにコードを実行すると何が起こるかを見るのは、実際に興味深いことですquacker.pyx
。その場合、initcaller()
関数はモジュールをインポートしようとしますquacker
が、quacker.py
またはがquacker.pyc
存在しないため、モジュールが見つからず、initcaller()
関数はエラーを生成します。
現在、このエラーは例外を発生させるという Python の方法で報告されています。しかし、main.c
ファイル内のコードはこれをチェックしていません。私はこの分野の専門家ではありませんが、私のテストでは以下のコードを追加するとinitcaller()
うまくいったようです。
if (PyErr_Occurred())
{
PyErr_Print();
return -1;
}
プログラムの出力は次のようになります。
Traceback (most recent call last):
File "caller.pyx", line 1, in init caller (caller.c:836)
from quacker import quack
ImportError: No module named quacker
initquacker()
関数を呼び出すことによって前に initcaller()
モジュール名はquacker
すでに登録されているため、内部で実行されるインポート呼び出しでは、initcaller()
すでにロードされていることが検出され、呼び出しは成功します。