"Cython" tutorial to make Python explosive: Pass a C ++ class object to a class object on the Python side. Part ①

Overview

I want to make the code written in C ++ a library that can be called in Python. However, there was a big wall called Cython.

This is a "Cython" tutorial that makes Python explosive: How to write setup.py when C ++ code depends on the library. It will be a continuation of.

The code is listed in "github here", so please take a look.

Up to the last time, I explained how to write setup.py to make C ++ code Cython when it depends on the library. The only function on the C ++ side used at that time was the void type. However, of course, I think that functions often write functions that return a value of some type rather than using void. This time, I will explain how to make a function that returns a type on the C ++ side instead of a void type into Cython and pass it to the Python side. If you understand this, you will be able to do a lot more, so please take a look.

Obviously, when using Cython to wrap a C ++ library for use in Python, the Python side does not automatically parse the C ++ class definition. Therefore, you have to define the class for Python properly on the Cython side and connect it with the C ++ side.

It's easy to write once you get used to it, but at first it's hard to know what to do, so I'll explain that.

Situation explanation

I want to pass an int or double.

As an example, write `test_sum``` that returns an int and `test_sum_double``` that returns a double on the C ++ side.

cpp_library/TestClass1.h


#include <gmp.h>

namespace my_library
{
class TestClass1{
    public:
        TestClass1();
        void test_function1();
        static void gmp_print_test();
        static int test_sum(int x, int y);
        static double test_sum_double(double x, double y);
};    
} // namespace my_library

cpp_library/TestClass1.cpp


#include <iostream>
#include "TestClass1.h"
using namespace std;

namespace my_library{

TestClass1::TestClass1(){};
void TestClass1::test_function1(){
    cout << "printed from cpp function" << endl;
}
void TestClass1::gmp_print_test(){
    mpz_t test;
    mpz_init(test);
    mpz_set_ui(test, 1);
    gmp_printf("print : %Zd \n", test);
}

int TestClass1::test_sum(int x, int y){
    return x+y;
}

double TestClass1::test_sum_double(double x, double y){
    return x+y;
}

}

At this point, the Cython code looks like this:

cython/test_class1.pxd


cdef extern from "../cpp_library/TestClass1.h" namespace "my_library":
    cdef cppclass TestClass1:
        TestClass1()
        void test_function1()
        void gmp_print_test()
        int test_sum(int x, int y)
        double test_sum_double(double x, double y)

cython/test_class1.pyx


import cython
cimport cython

cdef class TestClass1Cython:
    cdef TestClass1* ptr

    def __cinit__(self):
        self.ptr = new TestClass1()

    def __deadaloc(self):
        del self.ptr

    def test_function1_cython(self):
        self.ptr.test_function1()
    
    @staticmethod
    def gmp_print_test():
        cdef TestClass1 testclass1
        testclass1.gmp_print_test()

    @staticmethod
    def test_sum(int x, int y):
        cdef TestClass1 testclass1
        return testclass1.test_sum(x, y)

    @staticmethod
    def test_sum_double(float x, float y):
        cdef TestClass1 testclass1
        return testclass1.test_sum_double(x, y)

I want to pass a vector containing an int or double.

Suppose you have a C ++ implementation that returns a vector like this: It's just a test function that takes a list and returns a constant multiple of it. Write only the changed part of the class. (Since the implementation is the same for the vector pattern, I will omit it.)

cpp_library/TestClass1.h


static vector<int> test_vector_int(vector<int> x, int y);

cpp_library/TestClass.cpp



vector<int> TestClass1::test_vector_int(vector<int> x, int y){
    vector<int> result;
    result.resize(x.size());
    for(int i=0; i<x.size(); i++){
        result[i] = x[i]*y;
    }

    return result;
}

cython/test_class1.pxd


from libcpp.vector cimport vector	
from libcpp.string cimport string

cdef extern from "../cpp_library/TestClass1.h" namespace "my_library":
    cdef cppclass TestClass1:
        TestClass1()
        void test_function1()
        void gmp_print_test()
        int test_sum(int x, int y)
        double test_sum_double(double x, double y)
        vector[int] test_vector_int(vector[int] x, int y)

The above `from libcpp.vector cimport vector` recognizes the `` `vector ``` on the C ++ side, so there is not much to do on the Cython side. It can be implemented in the same way as a function that returns an int or double earlier.

cython/test_class1.pyx


    @staticmethod
    def test_vector_int(list x, int y):
        cdef TestClass1 testclass1
        return testclass1.test_vector_int(x,y)

If you actually do `` `python setup.py install```, you can see that the compilation goes through and you can call these functions from the Python side.

(myenv) root@e96f489c2395:/from_local/cython_practice# python 
Python 3.6.3 (default, Jan 30 2020, 06:37:54) 
[GCC 7.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import my_library
>>> my_library.TestClass1Cython.test_vector_int([1,2,3], 3)
[3, 6, 9]

I want to pass a custom class in the C ++ library.

Next, I will write it in an article.

Summary

This time, I explained that when converting a library written in C ++ to Cython so that it can be used from Python, the type declared in C ++ is passed to the Python side.

It turned out that if you pass an int or double itself, or a vector that has them as elements, it will be converted to an appropriate type on the Python side. It can be implemented surprisingly straightforwardly.

Next time, I will explain how to return an object of a class defined by yourself in C ++ code to the Python side. It's a little more complicated than ints, doubles, and vectors that have them as elements, but there are many situations like this in actual programs, so please take a look.

This time around here.

end.

Recommended Posts

"Cython" tutorial to make Python explosive: Pass a C ++ class object to a class object on the Python side. Part ①
"Cython" tutorial to make Python explosive: Pass the C ++ class object to the class object on the Python side. Part 2
"Cython" tutorial to make Python explosive: When a function on the C ++ side has an overload.
"Cython" tutorial to make Python explosive: Handling when a function on the C ++ side is passed by reference.
"Cython" tutorial to make Python explosive: When C ++ code depends on the library. Preparation
"Cython" tutorial to make Python explosive: When C ++ code depends on the library. Write setup.py.
"Cython" tutorial to make Python explosive: How to parse an Enum class defined in C ++ code into a Python Enum.
"Cython" tutorial to make Python explosive: When C ++ code depends on the library. First of all, CMake.
"Cython" Tutorial to Make Python Explosive: Basic Configuration
Make a breakpoint on the c layer with python
[Python] How to make a class iterable
Try to make a Python module in C language
[C / C ++] Pass the value calculated in C / C ++ to a python function to execute the process, and use that value in C / C ++.
How to use the __call__ method in a Python class
I tried to make a generator that generates a C # container class from CSV with Python
Pass OpenCV data from the original C ++ library to Python
[Python] I tried to make a simple program that works on the command line using argparse.
[Python + heroku] From the state without Python to displaying something on heroku (Part 1)
[Python + heroku] From the state without Python to displaying something on heroku (Part 2)
Pass a list by reference from Python to C ++ with pybind11
Introduction to Python Hands On Part 1
[Python] Make the function a lambda function
How to deal with "^ [[A ^ [[B ^ [[C ^ [[D"] when you press the arrow keys when executing python on mac
[Python] A progress bar on the terminal
[2015/11/19] How to register a service locally using the python SDK on naoqi os
How to pass the execution result of a shell command in a list in Python
Try porting the "FORTRAN77 Numerical Computing Programming" program to C and Python (Part 1)
Make a thermometer with Raspberry Pi and make it visible on the browser Part 3
[Python] Created a class to play sin waves in the background with pyaudio
Try porting the "FORTRAN77 Numerical Computing Programming" program to C and Python (Part 3)
[Python] Smasher tried to make the video loading process a function using a generator
Try porting the "FORTRAN77 Numerical Computing Programming" program to C and Python (Part 2)
Convert the cURL API to a Python script (using IBM Cloud object storage)
C language to see and remember Part 3 Call C language from Python (argument) c = a + b
Python C / C ++ Extensions: Pass some of the data as np.array to Python (set stride)
A memo of a tutorial on running python on heroku
How to use the C library in Python
Try to solve the Python class inheritance problem
A note on customizing the dict list class
I want to make a game with Python
Make a copy of the list in Python
How to generate a Python object from JSON
Try to make a "cryptanalysis" cipher with Python
Python: Prepare a serializer for the class instance:
Introduction to Python with Atom (on the way)
Save the object to a file with pickle
Try to make a dihedral group with Python
A python amateur tries to summarize the list ②
I want to make C ++ code from Python code!
[Python] Throw a message to the slack channel
I did a little research on the class
Lark Basics (Python, Lark to make a shell-like guy)
[Python] You can save an object to a file by using the pickle module.
Make it easy to install the ROS2 development environment with pip install on Python venv
How to pass arguments when invoking python script from blender on the command line
Let's make a leap in the manufacturing industry by utilizing the Web in addition to Python
Don't take an instance of a Python exception class directly as an argument to the exception class!