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 Bridge from C ++ to Python "Cython" course: How to pass a C ++ class object to a class object on the Python side. Part 2 is a continuation.
As usual, I'll post the code on github here so please have a look! !!
Suppose you define an Enum class on the C ++ side and have it as a property of the class. At this time, when you get this property using getter etc., the return value is of course the Enum class. When converting this to Cython, this return value is a class that is not defined on the Python side, so it is necessary to parse and return it after defining it in Cython.
First, let's take a quick look at how to write Enums in C ++ and Python.
enum class Color{
RED = 0,
GREEN = 1,
BLUE = 2
};
class Color(Enum):
RED = 0
GREEN = 1
BLUE = 2
Add the property (group) of the Enum class to TestClass1.h and TestClass1.cpp that have been written so far. We also added getters and setters for the group property accordingly.
cpp_library/TestClass1.h
enum class EnumForTestClass1{
ZERO = 0,
ONE = 1
};
class TestClass1{
private:
TestClass2 property_test_class2;
EnumForTestClass1 group;
public:
//~abridgement
void set_group(EnumForTestClass1 group);
EnumForTestClass1 get_group();
cpp_library/TestClass1.cpp
EnumForTestClass1 TestClass1::get_group(){
return this->group;
}
void TestClass1::set_group(EnumForTestClass1 group){
this->group = group;
}
This getter and setter are converted to cython, that is, the Enum class on the C ++ side and the Enum class on the Python side are connected.
As usual
cytyon/test_class1.C to pxd++Define the side Enum class. The definition method is divided according to the file below.
After that, add the definitions of the created getter and setter.
#### **`cython/test_class1.pxd`**
```pxd
cdef extern from "../cpp_library/TestClass1.h":
cdef cppclass EnumForTestClass1:
EnumForTestClass1()
cdef extern from "../cpp_library/TestClass1.h" namespace "my_library":
cdef EnumForTestClass1 ZERO
cdef EnumForTestClass1 ONE
cdef extern from "../cpp_library/TestClass1.h" namespace "my_library":
cdef cppclass TestClass1:
#~abridgement
void set_group(EnumForTestClass1 group)
EnumForTestClass1 get_group();
Also, add the same description to cython / my_library.pxd
.
cython/my_library.pxd
cdef extern from "../cpp_library/TestClass1.h" namespace "my_library":
cdef cppclass EnumForTestClass1:
EnumForTestClass1()
cdef extern from "../cpp_library/TestClass1.h" namespace "my_library":
cdef EnumForTestClass1 ZERO
cdef EnumForTestClass1 ONE
cdef extern from "../cpp_library/TestClass1.h" namespace "my_library":
cdef cppclass TestClass1:
#~abridgement
void set_group(EnumForTestClass1 group)
EnumForTestClass1 get_group();
Once this is done, the next step is to write the contents of the getter and setter in cython / tests_class1.pyx
.
If you write the code first, it will look like this:
cython/tests_class1.pyx
cpdef enum Py_EnumForTestClass1:
Py_ZERO = 0
Py_ONE = 1
cdef class TestClass1Cython:
cdef TestClass1* ptr
def set_group(self, Py_EnumForTestClass1 group):
return self.ptr.set_group(<EnumForTestClass1> group)
def get_group(self):
cdef:
EnumForTestClass1* cpp_enum_for_test_class1 = new EnumForTestClass1()
cpp_enum_for_test_class1[0] = <EnumForTestClass1>self.ptr.get_group()
if(<int>cpp_enum_for_test_class1[0] == <int>Py_EnumForTestClass1.Py_ZERO):
return Py_EnumForTestClass1.Py_ZERO
elif(<int>cpp_enum_for_test_class1[0] == <int>Py_EnumForTestClass1.Py_ONE):
return Py_EnumForTestClass1.Py_ONE
First, define the Enum class that can be called from Python with `` `cpdef enum Py_EnumForTestClass1```.
Next, regarding the setter, `Py_EnumForTestClass1``` is received from the Python side, and it is passed to the C ++ side function by casting it to the C ++ side type with
<EnumForTestClass1>
``.
Also, although the getter is a little redundant, what was passed as an Enum object on the C ++ side in `<EnumForTestClass1> self.ptr.get_group ()`
is cast with Py_EnumForTestClass1` `` on the Python side is equal to, and returns the `` `Py_EnumForTestClass1
object accordingly.
With the above, it is possible to parse the Enum class on the Python side to the Enum class on the C ++ side, and the Enum class on the C ++ side to the Enum class on the Python side.
Finally, as always
python setup.py install
Compile with and test it.
#### **`test.py`**
```py
import my_library as myl
if __name__ == "__main__":
cl1 = myl.test()
test1 = myl.Py_EnumForTestClass1.Py_ZERO
cl1.set_group(test1)
test2 = cl1.get_group()
print(test2)
as a result,
(myenv) root@e96f489c2395:/from_local/cython_practice# python test.py
0
It was confirmed that the Enum class could be set and get to the C ++ property.
This time, I explained how to pass the Enum class declared in C ++ to the Enum class on the Python side when converting a library written in C ++ to Cython so that it can be used from Python.
By now, I think most C ++ custom objects can be passed to Python.
Next time, I would like to write about how Cython handles function overloads, which are often written on the C ++ side.
This time around.
end.
Recommended Posts