如何异步重定向嵌入的Python的stdout/stdin到C++?

16 投票
3 回答
4922 浏览
提问于 2025-04-17 05:13

我其实是在尝试为一个嵌入的Python脚本写一个控制台界面,用来处理输入和输出。按照这里的说明,我成功捕获了标准输出(stdout):

Py_Initialize();
PyRun_SimpleString("\
class StdoutCatcher:\n\
    def __init__(self):\n\
        self.data = ''\n\
    def write(self, stuff):\n\
        self.data = self.data + stuff\n\
import sys\n\
sys.stdout = StdoutCatcher()");

PyRun_SimpleString("some script");

PyObject *sysmodule;
PyObject *pystdout;
PyObject *pystdoutdata;    
char *string;
sysmodule = PyImport_ImportModule("sys");
pystdout = PyObject_GetAttrString(sysmodule, "stdout");
pystdoutdata = PyObject_GetAttrString(pystdout, "data");    
stdoutstring = PyString_AsString(pystdoutdata);

Py_Finalize();

不过问题是,我只能在脚本运行完毕后才能收到标准输出,理想情况下,控制台应该是随着Python脚本的更新而实时更新输出内容。有没有办法做到这一点呢?

另外,我该如何捕获标准输入(stdin)呢?

如果有帮助的话,我正在使用一个支持Objective-C的编译器,并且可以使用boost库。


我已经搞定了标准输出的部分。为了记录下来,这样做是有效的:

static PyObject*
redirection_stdoutredirect(PyObject *self, PyObject *args)
{
    const char *string;
    if(!PyArg_ParseTuple(args, "s", &string))
        return NULL;
    //pass string onto somewhere
    Py_INCREF(Py_None);
    return Py_None;
}

static PyMethodDef RedirectionMethods[] = {
    {"stdoutredirect", redirection_stdoutredirect, METH_VARARGS,
        "stdout redirection helper"},
    {NULL, NULL, 0, NULL}
};

//in main...
    Py_Initialize();
    Py_InitModule("redirection", RedirectionMethods);
    PyRun_SimpleString("\
import redirection\n\
import sys\n\
class StdoutCatcher:\n\
    def write(self, stuff):\n\
        redirection.stdoutredirect(stuff)\n\
sys.stdout = StdoutCatcher()");

    PyRun_SimpleString("some script");

    Py_Finalize();

不过我还是在标准输入这块遇到麻烦...

3 个回答

0

如果你按照你提到的方法来做,把你的类继承自 io.IOBase 可能是个不错的选择。

1

到目前为止,我找到的最简单的方法如下:

PyObject *sys = PyImport_ImportModule("sys");
PyObject* io_stdout = PyFile_FromFile(stdout, "stdout", "a", nullptr);
PyObject_SetAttrString(sys, "stdout", io_stdout);
PyObject* io_stderr = PyFile_FromFile(stderr, "stderr", "a", nullptr);
PyObject_SetAttrString(sys, "stderr", io_stderr);
PyObject* io_stdin = PyFile_FromFile(stdin, "stdin", "r", nullptr);
PyObject_SetAttrString(sys, "stdin", io_stdin);

你可以用以下代码来测试:

# for test
PyRun_SimpleString("print sys.stdin.readline()");
1

如果你想在Python中处理所有可用的输入,我推荐使用fileinput模块。

如果你想逐行处理输入命令,比如在交互式解释器中,你可能会觉得Python的raw_input函数很有用。

如果你想用类似你之前用过的助手类来重定向标准输入,那么你需要重写的函数是readline,而不是read。想了解更多信息,可以查看这个链接(还有关于raw_input的内容)。

希望这些对你有帮助,

Supertwang

撰写回答