根据纸条将参数增加到PyEval\u EvalCode

2024-04-25 08:26:01 发布

您现在位置:Python中文网/ 问答频道 /正文

在下面的MCVE中,将执行两个不同的脚本。两者都不做任何特别的事情,第一个脚本有一个空函数,第二个脚本实际上什么都不做。但是根据脚本PyEval_EvalCode是否增加传递的全局/本地字典。文件上什么也没说。但根据脚本,我有一个悬空字典后,它被执行。我以后什么时候要取消它们?或者我错过了什么?下面的C代码段输出传递的字典的refcount。你知道吗

我用标准的Python-2.7解释器在Windows上试过这个。你知道吗

#pragma comment(lib, "C:\\Python27\\libs\\python27.lib")
#include "C:\\Python27\\include\\Python.h"

static int execute(const char* script)
{
    PyObject* globals = PyDict_New();
    PyDict_SetItemString(globals, "__builtins__", PyEval_GetBuiltins());

    PyObject* code = Py_CompileString(script, "test", Py_file_input);
    if (!code)
    {
        PyErr_Print();
        return 0;
    }

    PyObject* result = PyEval_EvalCode((PyCodeObject*)code, globals, nullptr);
    Py_DECREF(code);

    if (!result)
    {
        PyErr_Print();
        return 0;
    }

    Py_DECREF(result);
    printf("Refcount of globals: %zd\n", globals->ob_refcnt);
    Py_DECREF(globals); // missing decref spotted by user2357112

    return 0;
}

int main()
{
    const char* script = nullptr;

    Py_Initialize();

    // First script contains a function
    script = 
        "def main():\n" \
        "    pass\n" \
        "main()\n";
    execute(script);

    // second script does nothing
    script = "12345";
    execute(script);

    Py_Finalize();
    return 0;
}

Tags: py脚本executereturn字典mainlibscript
2条回答

追根溯源之后,我意识到有一个循环引用。函数获取对globals字典的引用,字典使函数保持活动状态。在脚本执行后立即调用垃圾收集器可以解决问题,循环引用也得到解决。你知道吗

execute(script);
PyGC_Collect();

p.S.用户2357112在我的MCVE中发现了一个丢失的decref。你知道吗

额外的引用是函数自身对其全局变量dict的引用。您不必担心此引用,也不必减少该引用。你知道吗

您只需要执行decrefs就可以清除您拥有的引用。你知道吗

相关问题 更多 >