Question

Je me bats un peu avec l'API Python C. J'appelle une méthode python pour faire un jeu AI à environ 60 Hz. Il fonctionne plus du temps, mais chaque seconde ou l'appel aux résultats PyEval_CallObject une valeur de retour NULL. Si je détecte correctement l'erreur et continue en boucle, tout va bien pour la prochaine seconde ou, après quoi l'erreur se produit à nouveau.

Je pense que je suis en train de faire quelque chose de mal avec le comptage ref mais je ne peux pas savoir ce qu'il est:

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"));

Oui, je suis d'importer le module chaque itération. Est-ce nécessaire? Si je stocke pAiModule comme global, je reçois un accident dur après environ une seconde.

    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
       {

Je n'ai pas été en mesure de savoir comment extraire encore l'exception, que ce soit ... sans test pour toutes les exceptions

       }
    }

Suis-je encore près de faire ce droit? Comme je l'ai dit, cela fonctionne la plupart du temps, mais je voudrais vraiment comprendre pourquoi je reçois une erreur.

Merci d'avance pour toute aide.

Était-ce utile?

La solution

Vous pouvez appeler PyImport_Import() aussi souvent que vous le souhaitez, mais vous continuez de revenir le même objet module. Python met en cache les importations. En outre, au lieu de créer une nouvelle chaîne de Python et fuit la référence (et donc l'objet), vous devez simplement utiliser PyImport_ImportModule(), qui prend const char *.

PyImport_Import*() renvoie une nouvelle référence, cependant, vous devez appeler Py_DECREF() là-dessus lorsque vous avez terminé. Le stockage du module dans un global ne devrait pas être un problème, tant que vous possédez une référence à ce (que vous faites, ici.)

Dans votre appel à vous PyEval_CallObject() ne vérifiez pas le résultat de Py_BuildValue() pour les erreurs, et vous aussi ne pas appeler Py_DECREF() lorsque vous avez terminé avec elle, donc vous fuit cet objet aussi bien.

Afin de convertir un flotteur Python à un double C, vous devriez probablement appeler PyFloat_AsDouble() au lieu de déblayage environ avec PyArg_Parse() (et garder à l'esprit pour tester des exceptions)

Bas pour le traitement d'erreur réelle: PyErr_ExceptionMatches() est seulement utile lorsque vous voulez vraiment tester si l'exception correspond à quelque chose. Si vous voulez savoir si une exception a eu lieu, ou obtenir l'objet d'exception réelle, PyErr_Occurred() est ce que vous devez appeler. Elle retourne l'exception actuelle type (non l'objet d'exception réelle) comme une référence empruntée, ou NULL si aucune est définie. Si vous voulez simplement imprimer un retraçage à stderr, PyErr_Print() et PyErr_Clear() sont ce que vous voulez utiliser. Pour plus d'inspection à grains fins de l'erreur réelle dans votre code, PyErr_Fetch() vous obtient l'objet exception en cours et le retraçage qui lui est associée (il vous obtient les mêmes informations que sys.exc_info() dans le code Python.) All Things Considered vous voulez rarement obtenir ce profondément dans le traitement des exceptions dans le code C.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top