Rusty Python: Blending Performance with Flexibility
Overview
Python offers incredible developer velocity but often struggles with raw execution speed and strict type safety. By integrating Rust, you can offload computationally expensive tasks to a memory-safe, high-performance backend while maintaining a user-friendly Python interface. This tutorial explores how to bridge these languages to achieve the best of both worlds.
Prerequisites
To follow along, you should have a basic understanding of Python and Rust syntax. You will need the Rust toolchain (Cargo) and Python 3.x installed on your machine.
Key Libraries & Tools
- PyO3: A library providing Rust bindings for Python, allowing you to write native modules.
- Maturin: A build tool that simplifies building and publishing Rust-based Python packages.
- rust-import: A utility for dynamically importing Rust files directly into Python scripts without manual compilation steps.
Code Walkthrough
Exposing Rust Functions
First, we use the #[pyfunction] macro to mark functions for export. The PyResult type ensures that Rust errors translate correctly into Python exceptions.
use pyo3::prelude::*;
#[pyfunction]
fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
Ok((a + b).to_string())
}
Defining the Module
The #[pymodule] macro creates the bridge. Here, the function name in Rust must match the module name defined in your configuration.
#[pymodule]
fn pyo3_rust(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;
Ok(())
}
Complex Structs and Classes
You can export Rust structs as Python classes using #[pyclass] and #[pymethods]. This allows Python to interact with Rust data structures as if they were native objects.
#[pyclass]
struct Email {
pub subject: String,
}
#[pymethods]
impl Email {
#[new]
fn new(subject: String) -> Self {
Email { subject }
}
}
Syntax Notes
Pay close attention to Macros. Attributes like #[pyclass] and #[pyfunction] are the secret sauce that handles the boilerplate of the CPython API. Additionally, Rust structs don't support inheritance like Python classes, so we use impl blocks to define methods.
Practical Examples
This hybrid approach excels in data processing, cryptography, or any scenario where a Python loop becomes a bottleneck. By moving the logic to Rust, you gain thread safety and significant speed boosts.
Tips & Gotchas
Always use maturin develop during local development to automatically compile and install your module into your virtual environment. Remember that Rust error handling via Result must be mapped to PyResult to prevent the Python interpreter from crashing on unhandled panics.

Combining Rust and Python: The Best of Both Worlds?
WatchArjanCodes // 11:08
On this channel, I post videos about programming and software design to help you take your coding skills to the next level. I'm an entrepreneur and a university lecturer in computer science, with more than 20 years of experience in software development and design. If you're a software developer and you want to improve your development skills, and learn more about programming in general, make sure to subscribe for helpful videos. I post a video here every Friday. If you have any suggestion for a topic you'd like me to cover, just leave a comment on any of my videos and I'll take it under consideration. Thanks for watching!