Асинхронно перенаправить стандартный вывод / стандартный ввод из встроенного Python в C ++? - PullRequest
12 голосов
/ 29 октября 2011

По сути, я пытаюсь написать консольный интерфейс с вводом и выводом для встроенного скрипта Python. Следуя инструкциям здесь , я смог перехватить стандартный вывод:

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();

Проблема в том, что я получаю stdout только после того, как скрипт завершит работу, в то время как в идеале для консоли stdoutstring будет обновляться по мере обновления скриптом python. Есть ли способ сделать это?

Кроме того, как бы я занялся захватом стандартного ввода?

Если это поможет, я работаю с компилятором, который принимает Objective-C. У меня также есть библиотеки буста.


Я выяснил стандартную часть вопроса. Для потомков это работает:

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();

По-прежнему возникают проблемы с stdin ...

Ответы [ 3 ]

1 голос
/ 18 июня 2016

Я нашел самый простой способ сделать это следующим образом:

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 голос
/ 18 ноября 2011

Для обработки всех доступных входных данных внутри Python я бы порекомендовал модуль fileinput .

Если вы хотите обрабатывать ввод как построчные команды (например, в интерактивноминтерпретатор), вам может пригодиться функция python raw_input .

Для перенаправления ввода через стандартный класс, аналогичный тому, который вы использовали выше, переопределенная функция равна readline , а не read .См. эту ссылку для получения дополнительной информации об этом (а также raw_input).

Надеюсь, это поможет, Supertwang

0 голосов
/ 20 декабря 2011

Если вы придерживаетесь подхода, который вы обрисовали, наследование вашего класса от io.IOBase, вероятно, хорошая идея.

...