pybind11 Перенаправить Python sys.stdout на C ++ из print () - PullRequest
1 голос
/ 08 ноября 2019

У меня есть программа на С ++ со встроенным интерпретатором Python PyBind11, выполняющая следующий файл Python, она печатает непосредственно в std::cout

# test.py
print("text")

Программа на С ++, выполняющая файл:

#include <pybind11/embed.h>

namespace py = pybind11;

int main() {
    py::scoped_interpreter guard{};
    py::eval_file("test.py");
}

Другие решения, которые я нашел, требовали изменения файла python - как я могу перенаправить python sys.stdout в c ++ как std :: string без изменения кода python, используя только оператор print ()?

Ответы [ 2 ]

0 голосов
/ 08 ноября 2019

Эта проблема github описывает способ: https://github.com/pybind/pybind11/issues/1622

Копирование кода из этой проблемы дословно. Для его работы рекомендовался следующий бит:

#include <pybind11/pybind11.h>
namespace py = pybind11;

Из вопроса:

class PyStdErrOutStreamRedirect {
    py::object _stdout;
    py::object _stderr;
    py::object _stdout_buffer;
    py::object _stderr_buffer;
public:
    PyStdErrOutStreamRedirect() {
        auto sysm = py::module::import("sys");
        _stdout = sysm.attr("stdout");
        _stderr = sysm.attr("stderr");
        auto stringio = py::module::import("io").attr("StringIO");
        _stdout_buffer = stringio();  // Other filelike object can be used here as well, such as objects created by pybind11
        _stderr_buffer = stringio();
        sysm.attr("stdout") = _stdout_buffer;
        sysm.attr("stderr") = _stderr_buffer;
    }
    std::string stdoutString() {
        _stdout_buffer.attr("seek")(0);
        return py::str(_stdout_buffer.attr("read")());
    }
    std::string stderrString() {
        _stderr_buffer.attr("seek")(0);
        return py::str(_stderr_buffer.attr("read")());
    }
    ~PyStdErrOutStreamRedirect() {
        auto sysm = py::module::import("sys");
        sysm.attr("stdout") = _stdout;
        sysm.attr("stderr") = _stderr;
    }
};

Использование:

{
    PyStdErrOutStreamRedirect pyOutputRedirect{};
    py::print("hello world");
    // Other noisy python functions can be put here
    assert(pyOutputRedirect.stdoutString() == "hello world\n")
}
// sys.stdout is back to its original state
0 голосов
/ 08 ноября 2019

Что означает «захват» в этом контексте? В конечном счете, будь то Python или C ++, написание проходит через ОС. Если целью является просто отключить вывод, записать его в файл, отправить его другому процессу и т. Д., И т. Д., Вы можете перехватить весь вывод на этом уровне.

Вот пример, который подавляет все stdoutвывод для продолжительности сценария Python, затем восстанавливает, после чего стандартный вывод ведет себя как прежде (для Python и других):

#include <pybind11/embed.h>
#include <unistd.h>

namespace py = pybind11;

int main() {

    auto fdo = fileno(stdout);
    auto savefd = dup(fdo);
    auto f = fopen("/dev/null", "w");
    dup2(fileno(f), fdo);

    py::scoped_interpreter guard{};
    py::eval_file("test.py");

    fflush(stdout);
    dup2(savefd, fdo);
}
...