如何重新初始化嵌入式Python解释器?

时间:2011-10-13 13:04:34

标签: c++ python boost embed boost-python

我正在努力在我们的测试套件应用程序中嵌入Python。目的是使用Python运行多个测试脚本来收集数据并生成测试报告。一次测试运行的多个测试脚本可以创建可在下一个脚本中使用的全局变量和函数。

该应用程序还提供了在嵌入式解释器中导入的扩展模块,用于与应用程序交换一些数据。

但是用户也可以进行多次测试运行。我不想在多次测试运行之间共享那些全局变量,导入和交换的数据。我必须确保以真实状态重新启动以控制测试环境并获得相同的结果。

我应该如何重新初始化翻译?

我使用了Py_Initialize()和Py_Finalize(),但是在我第二次初始化我提供给解释器的扩展模块时,在第二次运行时得到一个异常。 文档warns against using it more than once

使用sub-interpreters似乎与扩展模块初始化有相同的警告。

我怀疑我的扩展模块初始化时出了问题,但我担心第三方扩展模块会出现同样的问题。

也许可以通过在其自己的进程中启动解释器来使其工作,以确保释放所有内存。

顺便说一下,我正在使用boost-python,它也使用Py_Finalize警告AGAINST!

有什么建议吗?

由于

3 个答案:

答案 0 :(得分:4)

这是我发现实现我想要的另一种方式,从解释器中的一个干净的石板开始。

我可以控制用于执行代码的全局和本地命名空间:

// get the dictionary from the main module
// Get pointer to main module of python script
object main_module = import("__main__");
// Get dictionary of main module (contains all variables and stuff)
object main_namespace = main_module.attr("__dict__");

// define the dictionaries to use in the interpreter
dict global_namespace;
dict local_namespace;

// add the builtins
global_namespace["__builtins__"] = main_namespace["__builtins__"];

然后我可以使用命名空间来执行pyCode中包含的代码:

exec( pyCode, global_namespace, lobaca_namespace );

当我想通过清理词典来运行我的测试的新实例时,我可以清理命名空间:

// empty the interpreters namespaces
global_namespace.clear();
local_namespace.clear();        

// Copy builtins to new global namespace
global_namespace["__builtins__"] = main_namespace["__builtins__"];

根据我想要执行的级别,我可以使用global = local

答案 1 :(得分:1)

如何使用code.IteractiveInterpreter

这样的事情应该这样做:

#include <boost/python.hpp>
#include <string>
#include <stdexcept>

using namespace boost::python;

std::string GetPythonError()
{
    PyObject *ptype = NULL, *pvalue = NULL, *ptraceback = NULL;
    PyErr_Fetch(&ptype, &pvalue, &ptraceback);
    std::string message("");
    if(pvalue && PyString_Check(pvalue)) {
        message = PyString_AsString(pvalue);
    }
    return message;
}

// Must be called after Py_Initialize()
void RunInterpreter(std::string codeToRun)
{
    object pymodule = object(handle<>(borrowed(PyImport_AddModule("__main__"))));
    object pynamespace = pymodule.attr("__dict__");

    try {
        // Initialize the embedded interpreter
        object result = exec(   "import code\n"
                                "__myInterpreter = code.InteractiveConsole() \n", 
                                pynamespace);
        // Run the code
        str pyCode(codeToRun.c_str());
        pynamespace["__myCommand"] = pyCode;
        result = eval("__myInterpreter.push(__myCommand)", pynamespace);
    } catch(error_already_set) {
        throw std::runtime_error(GetPythonError().c_str());
    }
}

答案 2 :(得分:0)

我每次都会编写另一个shell脚本,用新的python实例执行测试脚本序列。或者像在

中一样用python编写
# run your tests in the process first
# now run the user scripts, each in new process to have virgin env
for script in userScript:
    subprocess.call(['python',script])