pybind11 将 python sys.stdout 从 print() 重定向到 c++

jai*_*ysc 5 c++ python pybind11

我有一个带有 pybind11 嵌入式 python 解释器的 c++ 程序,执行以下 python 文件,它直接打印到std::cout

# test.py
print("text")
Run Code Online (Sandbox Code Playgroud)

执行该文件的c++程序:

#include <pybind11/embed.h>

namespace py = pybind11;

int main() {
    py::scoped_interpreter guard{};
    py::eval_file("test.py");
}
Run Code Online (Sandbox Code Playgroud)

我发现的其他解决方案需要修改 python 文件 - 如何将 python sys.stdout 作为 std::string 重定向到 c++,而不仅使用 print() 语句修改 python 代码?

par*_*omi 3

这个github问题描述了一种方法: https: //github.com/pybind/pybind11/issues/1622

逐字复制该问题中的代码。建议使用以下位来使其工作:

#include <pybind11/pybind11.h>
namespace py = pybind11;
Run Code Online (Sandbox Code Playgroud)

从问题来看:

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;
    }
};
Run Code Online (Sandbox Code Playgroud)

用法:

{
    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
Run Code Online (Sandbox Code Playgroud)