Frage

Ich bin ein wenig mit dem Python-C-API zu kämpfen. Ich rufe eine Python-Methode einige Spiele AI bei etwa 60 Hz zu tun. Es funktioniert die meisten der Zeit, aber jede Sekunde oder so der Aufruf an PyEval_CallObject führt zu einem Rückgabewert NULL. Wenn ich richtig die Fehler erkennen und weiterhin Looping, alles ist gut für die nächste Sekunde oder so, worauf der Fehler erneut auftritt.

Ich vermute, ich tue etwas falsch mit ref Zählen, aber ich kann nicht herausfinden, was es ist:

int script_do_ai(struct game_data_t* gd)
{

    PyObject *pAiModule, *pResult;

    float result=0.0;
    pResult = NULL;

    pAiModule = PyImport_Import(PyString_FromString("ai_script"));

Ja, ich bin den Import der das Modul jede Iteration. Ist das nötig? Wenn ich pAiModule als globales speichern, ich einen harten Absturz erhalte nach etwa einer Sekunde.

    pResult = PyEval_CallObject(PyObject_GetAttrString(pAiModule, "do_ai"),
                               Py_BuildValue("f", gd->important_float))  
    if (pResult != NULL)
    {       
        PyArg_Parse(pResult, "f", &result);
        Py_DECREF(pResult);
        ConquerEnemies(result);  //you get the idea
    }
    else  //this happens every 75 or so iterations thru the loop
    {
       if (PyErr_ExceptionMatches(PyExc_SomeException))  //? not sure what to do here
       {

Ich habe nicht in der Lage gewesen, um herauszufinden, wie die Ausnahme noch zu extrahieren, entweder ... ohne Prüfung auf alle Ausnahme

       }
    }

Bin ich einmal in der Nähe dieses Recht zu tun? Wie ich schon sagte, es funktioniert meistens, aber ich möchte wirklich zu verstehen, warum ich eine Störung erhalte.

Vielen Dank im Voraus für jede Hilfe.

War es hilfreich?

Lösung

Sie können PyImport_Import() so oft nennen, wie Sie wollen, aber Sie werden nur immer das gleiche Modul-Objekt zurück zu bekommen. Python-Caches Importe. Auch, anstatt einen neuen Python-String zu erstellen und zu undichten die Referenz (und somit das Objekt), sollten Sie nur verwenden PyImport_ImportModule(), die ein const char * nimmt.

PyImport_Import*() eine neue Referenz zurückkehren, obwohl, sollten Sie Py_DECREF() auf sie anrufen, wenn Sie fertig sind. das Modul in einem globalen Speicherung sollte kein Problem, so lange, wie Sie es einen Verweis besitzen (was Sie tun, hier.)

In Ihrem Aufruf zum PyEval_CallObject() Sie sind nicht das Ergebnis von Py_BuildValue() auf Fehler überprüft, und Sie sind auch nicht Py_DECREF() aufrufen, wenn Sie mit ihm fertig sind, so dass Sie das Objekt auch sind undicht.

Um einen Python Schwimmer auf einen C-Doppel zu konvertieren, sollten Sie vielleicht rufen Sie einfach PyFloat_AsDouble() statt über mit PyArg_Parse() von Ausmisten (und im Kopf behalten Ausnahmen Test)

Bis auf die tatsächliche Fehlerbehandlung: PyErr_ExceptionMatches() ist nur dann sinnvoll, wenn Sie tatsächlich testen wollen, ob die Ausnahme etwas übereinstimmt. Wenn Sie, ob eine Ausnahme aufgetreten wissen wollen, oder das aktuelle Ausnahmeobjekt erhalten, ist PyErr_Occurred() was sollten Sie anrufen. Es gibt die aktuelle Ausnahme type (nicht das tatsächliche Ausnahmeobjekt) als entlehnt Referenz oder NULL, wenn kein festgelegt ist. Wenn Sie wollen einfach nur eine Rückverfolgung zu stderr, PyErr_Print() und PyErr_Clear() drucken sind, was Sie verwenden möchten. Für weitere feinkörnige Kontrolle des tatsächlichen Fehler im Code, erhält PyErr_Fetch() Sie das aktuelle Objekt Ausnahme und die Zurückverfolgungs mit ihm verbunden (es bekommt man die gleichen Informationen wie sys.exc_info() in Python-Code.) Alles in allem Sie selten bekommen möchten, dass tief in die Ausnahmebehandlung in C-Code.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top