PyO3 Notes
1. Introduction to PyO3
PyO3 allows Rust code to interface with Python, enabling the creation of Python modules and embedding Python in Rust applications. It provides Rust bindings for the Python C API.
2. Setting Up PyO3
To use PyO3, add the following to Cargo.toml
:
For a binary application embedding Python:
Enable the extension-module
feature only when building a Python extension.
3. Creating a Python Module in Rust
Create a Rust library and add lib.rs
:
use pyo3::prelude::*;
#[pyfunction]
fn add(a: i32, b: i32) -> PyResult<i32> {
Ok(a + b)
}
#[pymodule]
fn mymodule(py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(add, m)?)?;
Ok(())
}
Compile it to a Python module using maturin
:
Then use it in Python:
4. Working with Python Objects in Rust
use pyo3::types::PyDict;
use pyo3::prelude::*;
#[pyfunction]
fn create_dict(py: Python) -> PyResult<PyObject> {
let dict = PyDict::new(py);
dict.set_item("key", "value")?;
Ok(dict.into())
}
5. Calling Python from Rust
use pyo3::prelude::*;
fn main() {
Python::with_gil(|py| {
let sys = py.import("sys").unwrap();
let version: String = sys.getattr("version").unwrap().extract().unwrap();
println!("Python version: {}", version);
});
}
6. Using Rust Structs in Python
use pyo3::prelude::*;
#[pyclass]
struct Person {
#[pyo3(get, set)]
name: String,
}
#[pymethods]
impl Person {
#[new]
fn new(name: String) -> Self {
Person { name }
}
}
#[pymodule]
fn mymodule(py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<Person>()?;
Ok(())
}
7. Handling Python Exceptions in Rust
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
#[pyfunction]
fn fail() -> PyResult<()> {
Err(PyValueError::new_err("An error occurred"))
}
8. Embedding Python in a Rust Binary
use pyo3::prelude::*;
fn main() {
Python::with_gil(|py| {
let locals = [("x", 5)].into_py_dict(py);
py.run("print(x * 2)", None, Some(&locals)).unwrap();
});
}
9. Async Python with Tokio and PyO3
use pyo3::prelude::*;
use pyo3_asyncio::tokio::future_into_py;
use tokio::time::{sleep, Duration};
#[pyfunction]
fn async_function(py: Python) -> PyResult<PyObject> {
future_into_py(py, async move {
sleep(Duration::from_secs(2)).await;
Ok("Done!")
})
}
10. Compiling and Using PyO3 Modules
- Build the module:
maturin build
- Install locally:
maturin develop
- Run in Python:
import mymodule