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 it up! PyO3 Tutorial: Wrapping a Simple Function Part ➁

It will be a continuation of.

Target

Define a Rust class (struct + method) and call it from Python The goal is that.

This time, I will explain how to parse a class and how to call getters and setters via PyO3.

procedure

Use the project you created last time with cargo new --lib example. Of course, there is no problem even if you make a new one.

Class declaration

Write the following in lib.rs.


//lib.rs

use pyo3::prelude::*;
// ======================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,
}

here,


#[pyclass(module = "my_class")]

Allows you to call from Python via PyO3. I wrote (module =" my_class ") as a spell, but I don't really understand what it means. I'm sorry.

Here, MyClass is defined as Struct and as a property It has num: i32 and debug: bool.

First, write a constructor so that you can call this class as a Python object.


#[pymethods]
impl MyClass{
    #[new]
    fn new(num:i32, debug:bool) -> Self{
        MyClass{
            num: num,
            debug: debug
        }
    }

Here, on top of ʻimpl`

#[pymethods]

Is declared (decorated?), Also above the fn new (num: i32, debug: bool) that shows the constructor

#[new]

Note that it has been declared.

Adding a class to a module

Add this to the module as in the previous function:


//lib.rs

use pyo3::{wrap_pyfunction};
// =================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(())
}

here,

m.add_class::<MyClass>()?;

Line adds MyClass to the module.

Add getter and setter

This time, in addition to the class declaration, I will write the property getter and setter so that they can be called from Python.

//lib.rs

#[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(())
    }
}

In this way, you can also call getters and setters from Python via PyO3 by using the # [getter] and # [setter] decorators.

This time I wrote only about the property num. Regarding the return value of getter, since the type of num is ʻi32, the Python side receives it as PyResult . There is no return value for setter, so you can write PyResult <()>`.

Both when passing a Python object,


Ok(self.num)

Ok(())

Handing over using is the same as last time.

Compile using setup.py

setup.py and Cargo.toml are the same as last time, but just in case,

Cargo.toml


[package]
name = "test"
version = "0.1.0"
edition = "2018"

[lib]
name = "test_library"
crate-type = ["cdylib"]

[dependencies.pyo3]
version = "0.9.1"
features = ["extension-module"]

setup.py


from setuptools import setup
from setuptools_rust import Binding, RustExtension

setup(name='ope_rust',
        version='0.1',
        rust_extensions=[
            RustExtension('ope_rust', 'Cargo.toml',
                binding=Binding.PyO3)],
            zip_safe=False)

It will be.

python setup.py install

You can compile by doing.

Test run

When you run the following test program,

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)
$ python test.py

test for class
2
4

It turns out that we were able to construct the class and execute the get and set properties.

Summary

The goal, Define a Rust class (struct + method) and call it from Python It was, This time I explained how to call a class written in Rust from Python.

The class constructor and property getters and setters could also be called from Python via PyO3.

Next time, I'd like to add some methods of the class and explain various type conversions.

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
Changes from Python 2 to Python 3.0
Wrap C/C ++ with SWIG to speed up Python processing. [Overview]
How to call Python or Julia from Ruby (experimental implementation)