|
Packit |
534379 |
Utilities
|
|
Packit |
534379 |
#########
|
|
Packit |
534379 |
|
|
Packit |
534379 |
Using Python's print function in C++
|
|
Packit |
534379 |
====================================
|
|
Packit |
534379 |
|
|
Packit |
534379 |
The usual way to write output in C++ is using ``std::cout`` while in Python one
|
|
Packit |
534379 |
would use ``print``. Since these methods use different buffers, mixing them can
|
|
Packit |
534379 |
lead to output order issues. To resolve this, pybind11 modules can use the
|
|
Packit |
534379 |
:func:`py::print` function which writes to Python's ``sys.stdout`` for consistency.
|
|
Packit |
534379 |
|
|
Packit |
534379 |
Python's ``print`` function is replicated in the C++ API including optional
|
|
Packit |
534379 |
keyword arguments ``sep``, ``end``, ``file``, ``flush``. Everything works as
|
|
Packit |
534379 |
expected in Python:
|
|
Packit |
534379 |
|
|
Packit |
534379 |
.. code-block:: cpp
|
|
Packit |
534379 |
|
|
Packit |
534379 |
py::print(1, 2.0, "three"); // 1 2.0 three
|
|
Packit |
534379 |
py::print(1, 2.0, "three", "sep"_a="-"); // 1-2.0-three
|
|
Packit |
534379 |
|
|
Packit |
534379 |
auto args = py::make_tuple("unpacked", true);
|
|
Packit |
534379 |
py::print("->", *args, "end"_a="<-"); // -> unpacked True <-
|
|
Packit |
534379 |
|
|
Packit |
534379 |
.. _ostream_redirect:
|
|
Packit |
534379 |
|
|
Packit |
534379 |
Capturing standard output from ostream
|
|
Packit |
534379 |
======================================
|
|
Packit |
534379 |
|
|
Packit |
534379 |
Often, a library will use the streams ``std::cout`` and ``std::cerr`` to print,
|
|
Packit |
534379 |
but this does not play well with Python's standard ``sys.stdout`` and ``sys.stderr``
|
|
Packit |
534379 |
redirection. Replacing a library's printing with `py::print <print>` may not
|
|
Packit |
534379 |
be feasible. This can be fixed using a guard around the library function that
|
|
Packit |
534379 |
redirects output to the corresponding Python streams:
|
|
Packit |
534379 |
|
|
Packit |
534379 |
.. code-block:: cpp
|
|
Packit |
534379 |
|
|
Packit |
534379 |
#include <pybind11/iostream.h>
|
|
Packit |
534379 |
|
|
Packit |
534379 |
...
|
|
Packit |
534379 |
|
|
Packit |
534379 |
// Add a scoped redirect for your noisy code
|
|
Packit |
534379 |
m.def("noisy_func", []() {
|
|
Packit |
534379 |
py::scoped_ostream_redirect stream(
|
|
Packit |
534379 |
std::cout, // std::ostream&
|
|
Packit |
534379 |
py::module::import("sys").attr("stdout") // Python output
|
|
Packit |
534379 |
);
|
|
Packit |
534379 |
call_noisy_func();
|
|
Packit |
534379 |
});
|
|
Packit |
534379 |
|
|
Packit |
534379 |
This method respects flushes on the output streams and will flush if needed
|
|
Packit |
534379 |
when the scoped guard is destroyed. This allows the output to be redirected in
|
|
Packit |
534379 |
real time, such as to a Jupyter notebook. The two arguments, the C++ stream and
|
|
Packit |
534379 |
the Python output, are optional, and default to standard output if not given. An
|
|
Packit |
534379 |
extra type, `py::scoped_estream_redirect <scoped_estream_redirect>`, is identical
|
|
Packit |
534379 |
except for defaulting to ``std::cerr`` and ``sys.stderr``; this can be useful with
|
|
Packit |
534379 |
`py::call_guard`, which allows multiple items, but uses the default constructor:
|
|
Packit |
534379 |
|
|
Packit |
534379 |
.. code-block:: py
|
|
Packit |
534379 |
|
|
Packit |
534379 |
// Alternative: Call single function using call guard
|
|
Packit |
534379 |
m.def("noisy_func", &call_noisy_function,
|
|
Packit |
534379 |
py::call_guard
|
|
Packit |
534379 |
py::scoped_estream_redirect>());
|
|
Packit |
534379 |
|
|
Packit |
534379 |
The redirection can also be done in Python with the addition of a context
|
|
Packit |
534379 |
manager, using the `py::add_ostream_redirect() <add_ostream_redirect>` function:
|
|
Packit |
534379 |
|
|
Packit |
534379 |
.. code-block:: cpp
|
|
Packit |
534379 |
|
|
Packit |
534379 |
py::add_ostream_redirect(m, "ostream_redirect");
|
|
Packit |
534379 |
|
|
Packit |
534379 |
The name in Python defaults to ``ostream_redirect`` if no name is passed. This
|
|
Packit |
534379 |
creates the following context manager in Python:
|
|
Packit |
534379 |
|
|
Packit |
534379 |
.. code-block:: python
|
|
Packit |
534379 |
|
|
Packit |
534379 |
with ostream_redirect(stdout=True, stderr=True):
|
|
Packit |
534379 |
noisy_function()
|
|
Packit |
534379 |
|
|
Packit |
534379 |
It defaults to redirecting both streams, though you can use the keyword
|
|
Packit |
534379 |
arguments to disable one of the streams if needed.
|
|
Packit |
534379 |
|
|
Packit |
534379 |
.. note::
|
|
Packit |
534379 |
|
|
Packit |
534379 |
The above methods will not redirect C-level output to file descriptors, such
|
|
Packit |
534379 |
as ``fprintf``. For those cases, you'll need to redirect the file
|
|
Packit |
534379 |
descriptors either directly in C or with Python's ``os.dup2`` function
|
|
Packit |
534379 |
in an operating-system dependent way.
|
|
Packit |
534379 |
|
|
Packit |
534379 |
.. _eval:
|
|
Packit |
534379 |
|
|
Packit |
534379 |
Evaluating Python expressions from strings and files
|
|
Packit |
534379 |
====================================================
|
|
Packit |
534379 |
|
|
Packit |
534379 |
pybind11 provides the `eval`, `exec` and `eval_file` functions to evaluate
|
|
Packit |
534379 |
Python expressions and statements. The following example illustrates how they
|
|
Packit |
534379 |
can be used.
|
|
Packit |
534379 |
|
|
Packit |
534379 |
.. code-block:: cpp
|
|
Packit |
534379 |
|
|
Packit |
534379 |
// At beginning of file
|
|
Packit |
534379 |
#include <pybind11/eval.h>
|
|
Packit |
534379 |
|
|
Packit |
534379 |
...
|
|
Packit |
534379 |
|
|
Packit |
534379 |
// Evaluate in scope of main module
|
|
Packit |
534379 |
py::object scope = py::module::import("__main__").attr("__dict__");
|
|
Packit |
534379 |
|
|
Packit |
534379 |
// Evaluate an isolated expression
|
|
Packit |
534379 |
int result = py::eval("my_variable + 10", scope).cast<int>();
|
|
Packit |
534379 |
|
|
Packit |
534379 |
// Evaluate a sequence of statements
|
|
Packit |
534379 |
py::exec(
|
|
Packit |
534379 |
"print('Hello')\n"
|
|
Packit |
534379 |
"print('world!');",
|
|
Packit |
534379 |
scope);
|
|
Packit |
534379 |
|
|
Packit |
534379 |
// Evaluate the statements in an separate Python file on disk
|
|
Packit |
534379 |
py::eval_file("script.py", scope);
|
|
Packit |
534379 |
|
|
Packit |
534379 |
C++11 raw string literals are also supported and quite handy for this purpose.
|
|
Packit |
534379 |
The only requirement is that the first statement must be on a new line following
|
|
Packit |
534379 |
the raw string delimiter ``R"(``, ensuring all lines have common leading indent:
|
|
Packit |
534379 |
|
|
Packit |
534379 |
.. code-block:: cpp
|
|
Packit |
534379 |
|
|
Packit |
534379 |
py::exec(R"(
|
|
Packit |
534379 |
x = get_answer()
|
|
Packit |
534379 |
if x == 42:
|
|
Packit |
534379 |
print('Hello World!')
|
|
Packit |
534379 |
else:
|
|
Packit |
534379 |
print('Bye!')
|
|
Packit |
534379 |
)", scope
|
|
Packit |
534379 |
);
|
|
Packit |
534379 |
|
|
Packit |
534379 |
.. note::
|
|
Packit |
534379 |
|
|
Packit |
534379 |
`eval` and `eval_file` accept a template parameter that describes how the
|
|
Packit |
534379 |
string/file should be interpreted. Possible choices include ``eval_expr``
|
|
Packit |
534379 |
(isolated expression), ``eval_single_statement`` (a single statement, return
|
|
Packit |
534379 |
value is always ``none``), and ``eval_statements`` (sequence of statements,
|
|
Packit |
534379 |
return value is always ``none``). `eval` defaults to ``eval_expr``,
|
|
Packit |
534379 |
`eval_file` defaults to ``eval_statements`` and `exec` is just a shortcut
|
|
Packit |
534379 |
for ``eval<eval_statements>``.
|