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.
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)
Suppose you have a C ++ implementation that returns a vector
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]
Next, I will write it in an article.
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