This is Call Rust from Python to speed up! PyO3 Tutorial: Wrapping Classes Part ➀
It will be a continuation of.
The goal,
Define a Rust class (struct + method) and call it from Python
It was,
Last time I explained how to call a class written in Rust from Python.
The class constructor
and the property getter, setter
could also be called from Python via PyO3.
This time, I'll add some class methods and explain how to convert from Rust to Python type via PyO3
.
See ** PyO3's git repository ** (here),
I will explain how to pass a Rust object to the Python side with PyO3.
Vec
-> List
Hashmap
-> Dict
Vec
-> Tuple
Etc.
Use the project created by cargo new --lib example
up to the last time.
Of course, there is no problem even if you make a new one.
As a recap, last time I made it possible to call the getter
and setter
of the class constructor and property num
from Python via PyO3.
Below is the code I completed last time.
//lib.rs
use pyo3::prelude::*;
use pyo3::{wrap_pyfunction};
// ======================RUST CLASS TO PYTHON ======================================
/// Class for demonstration
// this class, MyClass can be called from python
#[pyclass(module = "my_class")]
struct MyClass {
num: i32,
debug: bool,
}
#[pymethods]
impl MyClass{
#[new]
fn new(num:i32, debug:bool) -> Self{
MyClass{
num: num,
debug: debug
}
}
#[getter]
fn get_num(&self) -> PyResult<i32>{
Ok(self.num)
}
#[setter]
fn set_num(&mut self, num: i32) -> PyResult<()>{
self.num = num;
Ok(())
}
}
// =================CREATING MODULE FOR PYTHON=========================
/// This module is a python module implemented in Rust.
#[pymodule]
fn test_library(py: Python, m: &PyModule) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(get_prime_numbers))?;
m.add_class::<MyClass>()?;
Ok(())
}
This time, we will add 6 functions to this MyClass
.
Immediately, the following is the code.
//lib.rs
use pyo3::types::PyType;
use pyo3::types::PyInt;
use pyo3::types::PyList;
use pyo3::types::PyTuple;
use pyo3::types::PyDateTime;
use std::collections::HashMap;
#[pymethods]
impl MyClass{
fn test1(&self) -> PyResult<bool>{
if self.num > 3{
Ok(true)
}else{
Ok(false)
}
}
fn test2(&self) -> PyResult<String>{
if self.debug == true{
let result: &str = "your debug is True";
Ok(result.to_string())
}else{
let result: &str = "your debug is False";
Ok(result.to_string())
}
}
fn test3<'py>(&self, py: Python<'py>) -> PyResult<&'py PyList>{
let mut vec = vec![1,2,3];
let result = PyList::new(py, &vec);
Ok(result)
}
fn test4(&self, py: Python) -> PyResult<PyObject>{
let mut map = HashMap::new();
map.insert("key1", 1);
map.insert("key2", 2);
map.insert("key3", 3);
assert_eq!(map["key1"], 1);
assert_eq!(map["key2"], 2);
assert_eq!(map["key3"], 3);
Ok(map.to_object(py))
}
fn test5(&self) -> PyResult<f64>{
let result:f64 = 1.23;
Ok(result)
}
fn test6<'py>(&self, py: Python<'py>, dt: &PyDateTime) -> PyResult<&'py PyTuple>{
let mut vec = vec![3,4,5];
let result = PyTuple::new(py, &vec);
Ok(result)
}
}
fn test1
Passing Rust bool
to Python bool
via PyO3.
fn test2
I'm passing a Rust String
to a Python str
via PyO3.
fn test3
Passing Rust's Vec
to Python's List
via PyO3.
I don't understand how to write this. ..
fn test4
I'm passing the Rust Hashmap
to the Python Dict
via PyO3.
fn test5
Passing Rust's f64
to Python's float
via PyO3.
fn test6
Passing Rust's Vec
to Python's tuple
via PyO3. At this time, Python Datetime
is received as an argument of the function.
I don't understand how to write this. ..
Regarding test3 and test6, I don't understand how to write honestly, but I will execute the test.
By preparing Cargo.toml
and setup.py
as before,
python setup.py install
You can build with.
Then prepare test.py
as follows and run the test.
test.py
import test_library
if __name__ == "__main__":
# Testing class
print("\ntest for class")
num = 2
debug = True
test = test_library.MyClass(num=num, debug=debug)
print(test.num) # getter test
test.num = 4 # setter test
print(test.num)
result = test.test1()
print(result)
print(type(result))
result = test.test2()
print(result)
print(type(result))
result = test.test3()
print(result)
print(type(result))
result = test.test4()
print(result)
print(type(result))
result = test.test5()
print(result)
print(type(result))
import datetime
now = datetime.datetime.now()
result = test.test6(now)
print(result)
print(type(result))
This time, I added some class methods and explained how to convert from Rust to Python type via PyO3.
Although it feels relatively easier to understand than Cython
, the version of PyO3
itself is being updated steadily, so the best thing is to develop it with the version in mind (Fix).
Or you should follow Git properly and pay attention to the change of API name.
However, Rust is interesting, so I will continue to study.
This time around here.
end.
Recommended Posts