Py_InitModule
を使用してコールバックを登録し、後で構造内の関数ポインタを新しい関数を指すように変更すると、新しい関数が呼び出されます。しかし、名前を変更すると、新しい名前は認識されません。Py_InitModuleは名前をコピーしますが、関数ポインタはコピーしませんか?
#include <Python.h>
PyObject* foo1(PyObject *self, PyObject *args)
{
printf("foo1\n");
Py_RETURN_NONE;
}
PyObject* foo2(PyObject *self, PyObject *args)
{
printf("foo2\n");
Py_RETURN_NONE;
}
int main()
{
PyMethodDef methods[] = {
{ "foo", foo1, METH_VARARGS, "foo" },
{ 0, 0, 0, 0 }
};
Py_Initialize();
Py_InitModule("foo", methods);
PyRun_SimpleString("import foo\n");
PyRun_SimpleString("foo.foo()\n");
methods[0].ml_meth = foo2;
PyRun_SimpleString("foo.foo()\n");
methods[0].ml_name = "foo2";
PyRun_SimpleString("foo.foo()\n");
PyRun_SimpleString("foo.foo2()\n");
return 0;
}
これは、次のような出力が得られます。
foo1 foo2 foo2 Traceback (most recent call last): File "", line 1, in AttributeError: 'module' object has no attribute 'foo2'
これは非常に一貫性のない行動です。 PyMethodDef methods
のスタック変数を使用したときに最初に遭遇しました。この変数は、変数が有効範囲外になったときにプログラムをクラッシュさせ、PythonからC++コールバックを呼び出そうとしました。だから私はポインタを変更すると実際には別のPy_InitModule
呼び出しでそれを再登録していないにもかかわらず呼び出される関数を変更することをテストしました。しかし同時に、名前を変更してもこの動作はありません。
は、これまでのところ私は(すなわち/ローカル変数スタックすることはできません)PyMethodDef
ニーズがある限りPythonのコードは、メソッドを呼び出そうとするために生きていることをかなり確信しているが、唯一の機能は、自身が使用されているポインタ。
これは意図的な動作ですか、一部の見落としですか?ドキュメントにはPyMethodDefの存続期間については何も触れていません。
これは予想されます。 'PyInit_Module'は何も初期化していないと思いましたか?それは後でそれらをチェックするのを避けるためにどの属性/メソッドが定義されているかをインタプリタに伝えます。関数の名前を動的に変更したい場合は、1)インタプリタからモジュールオブジェクトを取得します。2)PyObject_SetAttrを使って、モジュールオブジェクトの属性を設定するために、正確な名前を思い出しません。 – Bakuriu
@Bakuriuありがとうございます。しかし、なぜ 'ml_math'フィールドもコピーされていませんか?つまり、後で呼び出す関数をホットスワップするのはなぜですか? – sashoalm