The PyO3 `pymodule` attribute marks a Rust function as the initializer for a Python extension module. The function receives a Python interpreter handle and module object, then returns `PyResult<()>` after registering the module's contents. section 6.4 section 8.6
A minimal initializer can be empty, but useful modules add exported functions with `wrap_pyfunction!`. The resulting Rust library can be imported like an ordinary Python module while keeping its public API in Python. section 6.4 section 8.6
Registering a function
Mark `sum` with `#[pyfunction]`, then register it inside the initializer: `m.add_function(wrap_pyfunction!(sum, m)?)?;`. After building with maturin, Python can run `rust_json.sum(...)` just like a normal imported function. section 6.4
A compute module
A Mandelbrot extension uses `#[pymodule] fn mandelbrot(...)` to register `mandelbrot_func`. Python imports that module and submits the Rust function through a thread executor; a separate exported function can release the GIL for concurrency. section 8.6
Listing 6.9 Empty extension module
use pyo3::prelude::*;
#[derive(Debug, serde::Deserialize)]
struct Data {
name: String,
value: i32,
}
fn sum(input: &str) -> i32 {
let parsed: Data = serde_json::from_str(input).unwrap();
parsed.name.len() as i32 + parsed.value
}
#[pymodule]
fn rust_json(_py: Python, m: &PyModule) -> PyResult<()> {
Ok(())
}
Shows the smallest complete extension-module initializer alongside Rust code that is not yet exported. section 6.4
Listing 8.9 lib.rs: Creating the Python module
#[pymodule] #1
fn mandelbrot(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(mandelbrot_func, m)?)?; #2
Ok(())
}
Shows the practical pattern for creating a module and registering a PyO3 function. section 8.6
