python - PyEval_CallObject 偶尔会在循环中失败

标签 python c python-c-api

我在使用 Python C API 时遇到了一些困难。我正在调用 python 方法以大约 60hz 的频率执行一些游戏 AI。它在大部分 时间都有效,但每隔一秒左右,对 PyEval_CallObject 的调用都会导致 NULL 返回值。如果我正确检测到错误并继续循环,下一秒左右一切正常,然后错误再次发生。

我怀疑我在引用计数方面做错了什么,但我不知道它是什么:

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
       {

我还没有找到如何提取异常的方法,或者......没有测试每个异常

       }
    }

我什至接近做到这一点了吗?就像我说的,它大部分都有效,但我真的很想了解为什么我会收到错误。

提前感谢您的帮助。

最佳答案

您可以随心所欲地调用 PyImport_Import(),但您只会不断得到相同的模块对象。 Python 缓存导入。此外,与其创建新的 Python 字符串并泄漏引用(以及对象),不如使用 PyImport_ImportModule(),它采用 const char *

PyImport_Import*() 返回一个新引用,不过,您应该在完成后对其调用 Py_DECREF()。将模块存储在全局中应该不是问题,只要您拥有对它的引用(您在此处这样做。)

在调用 PyEval_CallObject() 时,您没有检查 Py_BuildValue() 的结果是否有错误,也没有调用 Py_DECREF( ) 当你完成它时,你也会泄漏那个对象。

为了将 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 代码中的异常处理。

关于python - PyEval_CallObject 偶尔会在循环中失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2234539/

相关文章:

python - 名称错误 : name 'plot_confusion_matrix' is not defined

python - Python 是否对字符串进行切片引用?

c - 如何让 valgrind 忽略特定行?

c - 将变量值视为地址并将该值赋给指针

Python C 扩展向异常添加属性

python - Pyparsing 中的贪婪表达式

python - 如何将可能格式错误的 xml 解析为数据框?

C: 为什么释放 int** 数组没有完成?

python - python c扩展模块中没有返回值的方法

c++ - 使用 Python 而不是 XML 在 C++ 中加载资源?