在C++程序中获取python的打印信息

我们希望在自己的C++程序中添加脚本支持,但是自己实现一套完整的脚本解释器会有许多额外的工作量,因此直接将python解释器嵌入到了我们的C++程序中,这样用户可以直接编写python脚本(类似Office的VBA脚本)操作我们的程序,大大方便了用户.

但是目前的问题是用户可能在python脚本中打印一些信息,我们需要获取python中打印的信息并将其显示在C++程序的log窗口中,经过笔者各种尝试终于可以获取到python脚本中使用print命令打印出来的信息了.由于python默认的print命令会将信息打印到sys.stdout,而这个对象实际上是一个TextIOWrapper类,因此理论上在这个类的write函数里就可以拿到具体的打印信息,我的思路是用C++实现一个自定义的write函数,借助python本身支持热替换类成员函数的特性,用它替换掉sys.stdout原本的write函数,然后我们就可以做任何我们想做的事了,比如拦截原本的输出信息,给输出信息添加时间戳等等,具体过程如下:

(我的开发环境为Windows10, Visual Studio 2019, Python 3.8)

1.首先在C++中实现一个write函数newWrite,该函数会将需要打印的信息传给原本的write函数,然后调用一个回调函数

2.然后将python环境中的sys.stdout自带的write()函数替换成我们自己编写的newWrite(),这样python每次print都会执行C++版本的newWrite()

#include "Python.h"
typedef void(*Callback)(const char*, size_t);
Callback gCb;
PyObject* gOriginalWriter;
PyObject* newWrite(PyObject* self, PyObject* args)
{
    PyObject* unicode;
    assert(!PyErr_Occurred());
    if (!PyArg_ParseTuple(args, "U", &unicode)
    {
        return nullptr;
    }
    Py_ssize_t n = 0;
    const char* str = PyUnicode_AsUTF8AndSize(unicode, &n);
    if (str == nullptr)
    {
        return nullptr;
    }
    PyObject* result = PyObject_CallFunctionObjArgs(gOriginalWriter, unicode, NULL);
    if (result == nullptr)
    {
        PyErr_Print();
        Py_RETURN_NONE;
    }
    else
    {
        gCb(str, n);  // do anything you want
        return PyLong_FromSsize_t(n);
    }
}

PyMethodDef writerFuncs[] =
{
    {"__my_write", newWrite, METH_VARARGS, ""},
    {NULL, NULL, 0, NULL}  // sentinel
};

int main()
{
    ...
    Py_Initialize();
    gCb = ...  // setup callback first
    
    // replace the original write() with our customized one
    PyObject* sys = PyImport_ImportModule("sys");
    PyModule_AddFunctions(sys, writerFuncs);
    PyObject* dict = PyModule_GetDict(sys);
    PyObject* stdout = PyDict_GetItemString(dict, "stdout");
    gOriginalWriter = PyObject_GetAttrString(stdout, "write");
    PyObject* newWriter = PyDict_GetItemString(dict, "__my_write");
    PyObject* key = PyUnicode_FromString("write");
    PyObject_SetAttr(stdout, key, newWriter);
    Py_DECREF(key);
    ...
}

你可能感兴趣的:(python,c++,开发语言)