Controlling Python from Rust Code¶
Initializing a Python Interpreter¶
Initializing an embedded Python interpreter in your Rust process is as simple
as calling
pyembed::MainPythonInterpreter::new(config: OxidizedPythonInterpreterConfig)
.
The hardest part about this is constructing the
pyembed::OxidizedPythonInterpreterConfig
instance.
Using a Python Interpreter¶
Once you’ve constructed a pyembed::MainPythonInterpreter
instance, you
can obtain a pyo3::Python
instance via .with_gil()
and then
use it:
fn do_it(interpreter: &MainPythonInterpreter) -> {
interpreter.with_gil(|py| {
match py.eval("print('hello, world')") {
Ok(_) => print("python code executed successfully"),
Err(e) => print("python error: {:?}", e),
}
});
}
Since CPython’s API relies on static variables (sadly), if you really wanted
to, you could call out to CPython C APIs directly (probably via the
bindings in the pyo3
crate) and they would interact with the
interpreter started by the pyembed
crate. This is all unsafe
, of course,
so tread at your own peril.
Finalizing the Interpreter¶
pyembed::MainPythonInterpreter
implements Drop
and it will call
Py_FinalizeEx()
when called. So to terminate the Python interpreter, simply
have the MainPythonInterpreter
instance go out of scope or drop it
explicitly.
A Note on the pyembed
APIs¶
The pyembed
crate is highly tailored towards PyOxidizer’s default use
cases and the APIs are not considered extremely well polished.
While the functionality should work, the ergonomics may not be great.
It is a goal of the PyOxidizer project to support Rust programmers who want
to embed Python in Rust applications. So contributions to improve the quality
of the pyembed
crate will likely be greatly appreciated!