Python 3 输出重定向使用C/C++
By:gddsky
目标
希望将Python 3的输出重定向到自定义的输出目标。
核心
Python使用sys.stdout、sys.stderr做输出目标,只要我们替换这两个值就可以重定向到我们自定义目标。替换的值的规则在Python的文档中sys (module)的sys.stdout上面说明只要添加一个write函数就可以了。像这样:
write(self, str)
我们只要在这个函数里面调用我们自己的输出函数就可以实现该目标了。
方案
在C++中写一个Python模块,并导入
在C++中利用PyRun_SimpleString建立一个PyObject去替换原始的sys.stdout、sys.stderr
搞定!!!
代码
模块定义部分代码(用python demo下的例子改写的)
static PyObject *console_write(PyObject *self, PyObject* args)
{
if (s_pyConsoleNotify != NULL)
{
const char* pMsgString=0;
if (!PyArg_ParseTuple( args, "s", &pMsgString ))
{
return NULL;
}
// 我们自己的输出函数
myprint(pMsgString);
}
Py_INCREF( Py_None );
return Py_None;
}
static PyMethodDef console_methods[] = {
{"test", console_test, METH_NOARGS, "Return the meaning of everything."},
{"write", console_write, METH_VARARGS, NULL},
{NULL, NULL} /* sentinel */
};
static struct PyModuleDef consolemodule = {
{}, /* m_base */
"console_capi", /* m_name */
0, /* m_doc */
0, /* m_size */
console_methods, /* m_methods */
0, /* m_reload */
0, /* m_traverse */
0, /* m_clear */
0, /* m_free */
};
PyObject* PyInit_console(void)
{
return PyModule_Create(&consolemodule);
}
用C++执行的Python代码
void myOutput()
{
PyImport_AppendInittab("console_capi", PyInit_console);
Py_Initialize();
PyRun_SimpleString(
"import sys/n"
"import console_capi/n"
"class XConsole:/n"
" def write(self, s):/n"
" console_capi.write(s)/n" // 这里将输出信息转给console_write函数
"myconsole = XConsole()/n"
"sys.stdout = myconsole/n"
"sys.stderr = myconsole"
);
}
经验
1. 用PyArg_ParseTuple函数做参数解析,怎么都是错误的,最后才发现原来是因为python的脚本里面写的console_capi.write(self, s),以为console_write(PyObject *self, PyObject* args)的self就是由脚本中的这个self传进来了,结果这个self与脚本的self不一样,它是module的PyObject,将console_capi.write(self, s)改成console_capi.write(s)之后,解析就对了。
2. 在C++中,可以看PyObject结构,里面有一个ob_type.tp_name的值,它直接显示这个Object是什么类型,比如说module、str、tuple,这个值让我们可以很方便的得到这个Object的类型,调试比较方便。
3. 一些问题实在麻烦,可以考虑直接下source版本编译Debug来调试,有些问题处理还是比较方便。