Ist es möglich, eine Python-Funktion aus einer Zeichenfolge zu laden und diese Funktion dann mit Argumenten aufzurufen und den Rückgabewert zu erhalten?
Ich verwende die Python-C-API, um Python-Code in meiner C++-Anwendung auszuführen. Ich kann ein Modul aus einer Datei laden mit PyImport_Import
erhalten Sie ein Funktionsobjekt davon mit PyObject_GetAttrString
und rufen Sie die Funktion mit auf PyObject_CallObject
. Ich möchte das Modul/die Funktion aus einer Zeichenfolge anstelle einer Datei laden. Gibt es etwas Äquivalent zu PyImport_Import
was würde es mir ermöglichen, eine Zeichenfolge anstelle einer Datei zu übergeben? Ich muss Argumente an die Funktion übergeben, die ich aufrufe, und ich brauche Zugriff auf den Rückgabewert, also kann ich nicht einfach verwenden PyRun_SimpleString
.
Bearbeiten:
Ich fand diese Lösung, nachdem ich eingeschaltet wurde PyRun_String
. Ich erstelle ein neues Modul, erhalte sein Wörterbuchobjekt und übergebe es in einem Aufruf an PyRun_String
um eine Funktion in meinem neuen Modul zu definieren, dann ein Funktionsobjekt für diese neu erstellte Funktion zu erhalten und es über aufzurufen PyObject_CallObject
, meine Argumente übergeben. Folgendes habe ich gefunden, um mein Problem zu lösen:
main.cpp
int main()
{
PyObject *pName, *pModule, *pArgs, *pValue, *pFunc;
PyObject *pGlobal = PyDict_New();
PyObject *pLocal;
//Create a new module object
PyObject *pNewMod = PyModule_New("mymod");
Py_Initialize();
PyModule_AddStringConstant(pNewMod, "__file__", "");
//Get the dictionary object from my module so I can pass this to PyRun_String
pLocal = PyModule_GetDict(pNewMod);
//Define my function in the newly created module
pValue = PyRun_String("def blah(x):\n\tprint 5 * x\n\treturn 77\n", Py_file_input, pGlobal, pLocal);
Py_DECREF(pValue);
//Get a pointer to the function I just defined
pFunc = PyObject_GetAttrString(pNewMod, "blah");
//Build a tuple to hold my arguments (just the number 4 in this case)
pArgs = PyTuple_New(1);
pValue = PyInt_FromLong(4);
PyTuple_SetItem(pArgs, 0, pValue);
//Call my function, passing it the number four
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
printf("Returned val: %ld\n", PyInt_AsLong(pValue));
Py_DECREF(pValue);
Py_XDECREF(pFunc);
Py_DECREF(pNewMod);
Py_Finalize();
return 0;
}
Hier ist der Rest meines ursprünglichen Beitrags, der der Nachwelt überlassen wurde:
Folgendes habe ich ursprünglich gemacht:
main.cpp
:
#include <Python.h>
int main()
{
PyObject *pName, *pModule, *pArgs, *pValue, *pFunc;
Py_Initialize();
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('')");
pName = PyString_FromString("atest");
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if(pModule == NULL)
{
printf("PMod is null\n");
PyErr_Print();
return 1;
}
pFunc = PyObject_GetAttrString(pModule, "doStuff");
pArgs = PyTuple_New(1);
pValue = PyInt_FromLong(4);
PyTuple_SetItem(pArgs, 0, pValue);
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
printf("Returned val: %ld\n", PyInt_AsLong(pValue));
Py_DECREF(pValue);
Py_XDECREF(pFunc);
Py_DECREF(pModule);
Py_Finalize();
return 0;
}
Und atest.py
:
def doStuff( x):
print "X is %d\n" % x
return 2 * x
Es ist nicht notwendig, Ihren Posten der Nachwelt zu hinterlassen. Stack Overflow hat das bereits abgedeckt. Alle Änderungen an Fragen und Antworten werden automatisch archiviert, was wir sehen können, sobald unsere Punkte ein bestimmtes Niveau erreichen. Das hilft uns, fehlerhafte Änderungen rückgängig zu machen und die Änderungen nachzuverfolgen, um Fragen besser zu verstehen. Anstatt es dort zu belassen, können Sie also Ihre Änderungen löschen und wir können uns bei Bedarf das Bearbeitungsprotokoll ansehen. Aus diesem Grund ist es nicht einmal notwendig, “Edit:” einzugeben.
– der Blechmann
14. Januar 2015 um 20:02 Uhr
Für andere, die darüber stolpern: Im ersten Codeschnipsel wird Py_Initialize zu spät aufgerufen. nur dass du es weißt
– Hallo Welt
3. April 2018 um 16:25 Uhr
Überprüfen Sie, ob Sie pValue zweimal verwenden, die erste Referenz muss ein Speicherleck verursachen
– themadmax
8. August 2018 um 9:33 Uhr
eine Frage: Die in einem einzelnen PyRun_String-Aufruf definierte Funktion muss vollständig in einem einzigen Aufruf enthalten sein? dh der Hauptteil der Funktion kann nicht in aufeinanderfolgende Aufrufe von PyRun_String aufgeteilt werden?
– Benutzer3181125
4. November um 18:16 Uhr