Je veux faire du code écrit en C ++ une bibliothèque qui puisse être appelée en Python. Cependant, il y avait un grand mur appelé Cython.
Il s'agit d'un tutoriel "Cython" qui rend Python explosif: Comment écrire setup.py lorsque le code C ++ dépend de la bibliothèque. Ce sera une continuation de.
Le code est répertorié dans "github here", veuillez donc y jeter un œil.
Jusqu'à la dernière fois, j'ai expliqué comment écrire setup.py pour créer du code C ++ Cython lorsque cela dépend de la bibliothèque. La seule fonction du côté C ++ utilisée à l'époque était le type void. Cependant, bien sûr, je pense que les fonctions écrivent souvent des fonctions qui renvoient des valeurs d'un certain type plutôt que d'utiliser void. Cette fois, je vais expliquer comment créer une fonction qui retourne un type du côté C ++ au lieu d'un type void en Cython et le passer du côté Python. Si vous comprenez cela, vous pourrez faire beaucoup plus, alors jetez un œil.
De toute évidence, lorsque vous utilisez Cython pour encapsuler une bibliothèque C ++ à utiliser en Python, le côté Python n'analyse pas automatiquement la définition de classe C ++. Par conséquent, vous devez définir correctement la classe pour Python du côté Cython et la connecter avec le côté C ++.
C'est facile à écrire une fois que l'on s'y est habitué, mais au début, il est difficile de savoir quoi faire, alors je vais vous l'expliquer.
Par exemple, écrivez test_sum``` qui renvoie int et
test_sum_double``` qui retourne double du côté C ++.
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;
}
}
À ce stade, le code Cython ressemble à ceci:
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)
Supposons que vous ayez une implémentation C ++ qui renvoie le vecteur
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)
Le
de libcpp.vector cimport vector` '' ci-dessus reconnaît le vecteur ''
du côté C ++, il n'y a donc pas grand chose à faire du côté Cython. Il peut être implémenté de la même manière qu'une fonction qui renvoie int ou double plus tôt.
cython/test_class1.pyx
@staticmethod
def test_vector_int(list x, int y):
cdef TestClass1 testclass1
return testclass1.test_vector_int(x,y)
Si vous effectuez réellement
python setup.py install '', vous pouvez confirmer que la compilation est réussie et ces fonctions peuvent être appelées du côté Python.
(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]
Ensuite, je l'écrirai dans un article.
Cette fois, j'ai expliqué que lors de la conversion d'une bibliothèque écrite en C ++ en Cython pour qu'elle puisse être utilisée depuis Python, le type déclaré en C ++ est passé du côté Python.
Il s'est avéré que si vous passez int ou double lui-même, ou un vecteur qui les a comme éléments, il sera converti en un type approprié du côté Python. Il peut être mis en œuvre de manière étonnamment simple.
La prochaine fois, j'expliquerai comment retourner un objet d'une classe définie par vous-même en code C ++ du côté Python. C'est un peu plus compliqué que int, double et vector avec eux comme éléments, mais il existe de nombreuses situations comme celle-ci dans les programmes réels, alors jetez un œil.
Cette fois par ici.
fin.
Recommended Posts