Call Rust from Python to speed it up! PyO3 Tutorial: Wrapping Classes Part ➁

Overview

  1. It is not preferable in terms of speed to write the algorithm in Pyhton ~
  2. Alright, look for something written around C, C ++ and call it from Python to speed it up.
  3. I can't find a good library,
  4. Oh, if it was written in a language called Rust
  5. Can Rust be called from Python? ??

This is Call Rust from Python to speed up! PyO3 Tutorial: Wrapping Classes Part ➀

It will be a continuation of.

Target

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.

Etc.

procedure

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. ..

Run test

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))

Summary

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

Call Rust from Python to speed it up! PyO3 Tutorial: Wrapping Classes Part ➀
Call Rust from Python to speed it up! PyO3 Tutorial: Wrapping Classes Part ➁
Call Rust from Python to speed it up! PyO3 Tutorial: Wrapping a Simple Function Part ➀
Call Rust from Python to speed it up! PyO3 Tutorial: Wrapping a Simple Function Part ➁
Go language to see and remember Part 8 Call GO language from Python
Call Matlab from Python to optimize
Numba to speed up as Python
How to speed up Python calculations
Don't write Python if you want to speed it up with Python
[Python] Hit Keras from TensorFlow and TensorFlow from c ++ to speed up execution
C language to see and remember Part 2 Call C language from Python (argument) string
C language to see and remember Part 1 Call C language from Python (hello world)
C language to see and remember Part 4 Call C language from Python (argument) double
C language to see and remember Part 5 Call C language from Python (argument) Array
C language to see and remember Part 3 Call C language from Python (argument) c = a + b
Study from Python Hour7: How to use classes
[Python] Do your best to speed up SQLAlchemy
An easy way to call Java from Python
From setting up Raspberry Pi to installing Python environment
[Python] How to call a c function from python (ctypes)
Changes from Python 3.0 to Python 3.5
Call C language functions from Python to exchange multidimensional arrays
Wrap C/C ++ with SWIG to speed up Python processing. [Overview]
From setting up a Rust environment to running Hello World
How to call Python or Julia from Ruby (experimental implementation)