Wenn ich Callbacks unter Verwendung Py_InitModule
registriere, und wenn ich später den Funktionszeiger in der Struktur ändere, um auf eine neue Funktion zu verweisen, wird die neue Funktion aufgerufen. Aber wenn ich den Namen ändere, wird der neue Name nicht erkannt.Py_InitModule kopiert den Namen, aber nicht den Funktionszeiger?
#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;
}
Dies ergibt die folgende Ausgabe:
foo1 foo2 foo2 Traceback (most recent call last): File "", line 1, in AttributeError: 'module' object has no attribute 'foo2'
Dies scheint ein sehr inkonsistentes Verhalten. Ich fand es zuerst, als ich eine Stapelvariable für PyMethodDef methods
verwendete, die das Programm abstürzte, nachdem die Variable den Gültigkeitsbereich verlassen hatte, und ich versuchte immer noch, den C++ - Callback von Python aufzurufen. Also habe ich getestet, dass das Ändern des Zeigers tatsächlich die aufgerufene Funktion ändert, obwohl ich sie nicht erneut mit einem anderen Py_InitModule
Aufruf registriert habe. Aber zur gleichen Zeit hat das Ändern des Namens dieses Verhalten nicht.
Bis jetzt bin ich mir ziemlich sicher, dass PyMethodDef
so lange leben muss, wie Python-Code versucht, die Methoden aufzurufen (d. H. Nicht Stack/lokale Variable sein), aber nur die Funktionszeiger selbst werden verwendet.
Ist dies ein absichtliches Verhalten oder eine gewisse Aufsicht? Die Dokumentation erwähnt nichts über PyMethodDef Lebenszeit, die ich finden konnte.
Dies wird erwartet. Was denkst du, dass das 'PyInit_Module' nichts initialisiert hat? Es teilt dem Interpreter mit, welches Attribut/welche Methoden definiert sind, um diese später zu vermeiden. Wenn Sie eine Funktion dynamisch umbenennen möchten, müssen Sie 1) das Modulobjekt vom Interpreter beziehen. 2) Verwenden Sie 'PyObject_SetAttr' (oder ähnlich, ich erinnere mich nicht an den genauen Namen), um das Attribut auf dem Modulobjekt zu setzen. – Bakuriu
@Bakuriu Danke, aber warum wird das 'ml_math'-Feld nicht ebenfalls kopiert? Das heißt, warum tauscht das spätere Ändern der Hot-Swap-Funktion die aufgerufene Funktion aus? – sashoalm