Scrivere moduli Python in Rust con PyO3
Il programma principale è codice Python, quindi ci serve un ambiente virtuale adatto. Immaginiamo di lavorare ad un progetto nuovo e creiamo una cartella. Questa sarà la nostra root.
All'interno della root lanciamo:
python3 -m venv env
Per entrare nell'ambiente appena creato:
source env/bin/activate
Ci serve un file in cui scrivere l'entry point del programma python.
Come è convenzione fare, lo chiamiamo main.py
. Per crearlo facilmente,
possiamo agire direttamente dal terminale e lanciare
touch main.py
Per il momento lasciamolo vuoto ed occupiamoci del vero codice, quello in rust. Lanciamo:
cargo new progetto
Cargo si occupa della parte più noiosa e crea i file utili per noi.
TODO: scrivere schema ASCII con gerarchia dei file
cd progetto
nano Cargo.toml
A questo punto modifichiamo così il file:
# Cargo.toml
[package]
name = "progetto"
version = "0.1.0"
authors = ["mr-chrome <giovanni.crisalfi@gmail.com>"]
edition = "2018"
[lib]
name = "progetto"
crate-type = ["cdylib"]
[dependencies.pyo3]
version = "0.12.4"
features = ["extension-module"]
Cosa abbiamo scritto?
Sotto [package]
le solite informazioni, quelle che servono per ogni progetto
in rust:
- il nome del progetto
- la versione che sarà aggiornata da noi in base allo stato di completamento del codice
- Gli autori con nick ed email
- L'edizione di Rust in uso
Sotto [lib]
è fondamentale scrivere lo stesso nome che utilizzeremo
all'interno del file src/lib.rs
che stiamo per scrivere. Infine le dipendenze.
Salviamo e passiamo al prossimo file.
nano src/lib.rs
Scrivere questo codice:
// src/lib.rs
use pyo3::prelude::*;
use pyo3::wrap_pyfunction;
/// Formats the sum of two numbers as string.
#[pyfunction]
fn say_hi_to(name: &str) -> PyResult<String> {
Ok(format!("Hi, {}!", name))
}
/// A Python module implemented in Rust.
#[pymodule]
fn progetto(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_pyfunction!(say_hi_to, m)?)?;
Ok(())
}
Nelle prime due righe abbiamo importato pyo3, dopodiché abbiamo sfruttato
una macro per dichiarare la nostra funzione.
La macro portante è quella finale, giacché lì è specificato il modulo sotto cui
verranno raccolte tutte le funzioni di cui abbiamo bisogn. Come si può notare,
ha lo stesso nome del progetto specificato in Cargo.toml
.
La funzione che abbiamo scritto non fa altro che prendere il nome che riceve come input e wrapparlo in una semplice frase che saluta l'interlocutore.
A questo punto salviamo il file e compiliamo:
cargo build --release
Per il prossimo comando è importante che il virtual env sia attivo. Se non lo è,
attivarlo adesso tornando nella root e digitando: source env/bin/activate
,
quindi tornare in progetto
e lanciare:
pip3 install maturin && maturin develop
A questo punto il nostro modulo dovrebbe essere disponibile per tutto l'ambiente python. Torniamo nella root:
nano main.py
Copiare questo codice:
# main.py
from progetto import say_hi_to
name = input("Digit your name:\n")
print(say_hi_to(name) + "\n")
input("Press any button to exit.")
Salvare il file e testare il programma:
python3 main.py
Il programma chiederà il tuo nome, facciamo Cromo
, quindi mosterà:
Digit your name:
Cromo
Hi, Cromo!
Press any button to exit.
Bene, il nostro modulo è stato importato con successo e la funzione ha svolto il proprio sacrosanto lavoro.
Questo post ti è stato utile?
Tieni a mente che questo sito è privo di tracker, analytics e pubblicità, quindi tutela la tua privacy ma non guadagna dalle visite (inoltre, è progettato per avere un impatto ambientale minimo).
Se ti piace questo blog, sostieni le mie riserve di caffeina