Асинхронно перенаправлять stdout/stdin из встроенного python в С++?
Я стараюсь писать консольный интерфейс со входом и выходом для встроенного python script. Следуя инструкциям здесь, я смог записать 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();
Проблема заключается в том, что я получаю только stdout после, закончил работу script, тогда как в идеале для консоли stdoutstring будет обновляться по мере обновления python script. Есть ли способ сделать это?
Кроме того, как бы я мог выполнить захват 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();
По-прежнему возникают проблемы с stdin...
Ответы
Ответ 1
Для обработки всего доступного ввода внутри Python я бы рекомендовал fileinput модуль.
Если вы хотите обрабатывать ввод в виде строк за строкой (например, в интерактивном интерпретаторе), вы можете найти функцию python raw_input полезно.
Для перенаправления stdin с использованием аналогичного вспомогательного класса, такого как те, которые вы использовали выше, функция переопределения - readline, а не читать. См. эту ссылку для получения дополнительной информации об этом (а также raw_input).
Надеюсь, это поможет,
Supertwang
Ответ 2
Самый простой способ, который я нашел до сих пор, заключается в следующем:
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()");
Ответ 3
Если вы придерживаетесь намеченного вами подхода, наследование вашего класса из io.IOBase, вероятно, хорошая идея.