代码之家  ›  专栏  ›  技术社区  ›  Nick Monkman

PyEval_CallObject偶尔在循环中失败

  •  2
  • Nick Monkman  · 技术社区  · 15 年前

    我在Python C API方面有点困难。我正在调用python方法来以大约60hz的频率执行一些游戏AI。它起作用了

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

    是的,我每次迭代都要导入模块。有必要吗?如果我将pAiModule存储为全局,大约一秒钟后就会发生严重崩溃。

        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
           {
    

    每一个 例外

           }
        }
    

    我是否已经接近做到这一点了?就像我说的,它大部分是有效的,但我真的很想理解为什么我会出错。

    1 回复  |  直到 15 年前
        1
  •  5
  •   Thomas Wouters    15 年前

    你可以打电话 PyImport_Import() 您可以随时使用,但只需不断获取相同的模块对象即可。Python缓存导入。此外,您应该使用 PyImport_ImportModule() const char *

    PyImport_Import*() 返回一个新的引用,但是,您应该调用 Py_DECREF() 当你完成的时候就开始。只要您拥有一个对模块的引用(在这里您是这样做的),将模块存储在全局文件中应该不会有问题

    在你的电话里 PyEval_CallObject() Py_BuildValue() 如果有错误,你也不会打电话 当你用完它的时候,你也在泄漏这个物体。

    为了将Python float转换为C double,您可能只需要调用 PyFloat_AsDouble() 而不是和我一起胡闹 PyArg_Parse() (请记住测试异常)

    PyErr_ExceptionMatches() 仅当您确实希望测试异常是否与某个内容匹配时,此选项才有用。如果要知道是否发生异常,或获取实际的异常对象, PyErr_Occurred() 类型 (不是实际的异常对象)作为借用引用,如果未设置,则为NULL。如果你想打印一份到stderr的回溯, PyErr_Print() PyErr_Clear() 是你想用的东西。要对代码中的实际错误进行更细粒度的检查, PyErr_Fetch() 获取当前异常对象及其关联的回溯(它获取的信息与 sys.exc_info() 在Python代码中。)您很少希望深入了解C代码中的异常处理。