Tutoriel "Cython" pour rendre Python explosif: Passez un objet de classe C ++ à un objet de classe côté Python. Partie ①

Aperçu

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.

Explication de la situation

Je veux passer int ou double.

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)

Je veux passer un vecteur contenant int et double.

Supposons que vous ayez une implémentation C ++ qui renvoie le vecteur comme ceci: C'est juste une fonction de test qui prend une liste et en renvoie un multiple constant. N'écrivez que la partie modifiée de la classe. (Étant donné que l'implémentation est la même pour le modèle vectoriel , je vais l'omettre.)

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]

Je souhaite transmettre une classe personnalisée dans une bibliothèque C ++.

Ensuite, je l'écrirai dans un article.

Résumé

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

Tutoriel "Cython" pour rendre Python explosif: Passez un objet de classe C ++ à un objet de classe côté Python. Partie ①
Tutoriel "Cython" pour rendre Python explosif: Passez l'objet de classe C ++ à l'objet de classe côté Python. Partie 2
Tutoriel "Cython" pour rendre Python explosif: Lorsqu'une fonction côté C ++ a une surcharge.
Tutoriel "Cython" qui rend Python explosif: Gérer le passage de fonctions côté C ++ par référence.
Tutoriel "Cython" qui rend Python explosif: lorsque le code C ++ dépend de la bibliothèque. Préparation
Tutoriel "Cython" qui rend Python explosif: lorsque le code C ++ dépend de la bibliothèque. Écrivez setup.py.
Tutoriel "Cython" pour rendre Python explosif: Comment analyser la classe Enum définie en code C ++ vers Enum en Python.
Tutoriel "Cython" qui rend Python explosif: lorsque le code C ++ dépend de la bibliothèque. Tout d'abord, CMake.
Tutoriel "Cython" pour rendre Python explosif: configuration de base
Faire un point d'arrêt sur la couche c avec python
[Python] Comment rendre une classe itérable
Essayez de créer un module Python en langage C
[C / C ++] Passez la valeur calculée en C / C ++ à une fonction python pour exécuter le processus et utilisez cette valeur en C / C ++.
Comment utiliser la méthode __call__ dans la classe Python
J'ai essayé de créer un générateur qui génère une classe conteneur C # à partir de CSV avec Python
Transmettez les données OpenCV de la bibliothèque C ++ d'origine à Python
[Python] J'ai essayé de créer un programme simple qui fonctionne sur la ligne de commande en utilisant argparse
[Python + heroku] De l'état sans Python à l'affichage de quelque chose avec heroku (Partie 1)
[Python + heroku] De l'état sans Python à l'affichage de quelque chose avec heroku (partie 2)
Passer la liste de Python vers C ++ par référence dans pybind11
Introduction à Python Hands On Partie 1
[Python] Faire de la fonction une fonction lambda
Comment gérer "^ [[A ^ [[B ^ [[C ^ [[D"]] en appuyant sur la touche de direction lors de l'exécution de python sur mac
[Python] Une barre de progression sur le terminal
[2015/11/19] Comment enregistrer un service localement à l'aide du SDK python avec naoqi os
Comment passer le résultat de l'exécution d'une commande shell dans une liste en Python
Essayez de porter le programme «Programmation informatique numérique FORTRAN77» vers C et Python (partie 1)
Fabriquez un thermomètre avec Raspberry Pi et rendez-le visible sur le navigateur Partie 3
[Python] A créé une classe pour jouer des vagues de péché en arrière-plan avec pyaudio
Essayez de porter le programme "FORTRAN77 Numerical Computing Programming" vers C et Python (partie 3)
[Python] Smasher a essayé de faire du processus de chargement de la vidéo une fonction à l'aide d'un générateur
Essayez de porter le programme "FORTRAN77 Numerical Computing Programming" vers C et Python (partie 2)
Convertir l'API cURL en script Python (à l'aide du stockage d'objets IBM Cloud)
Langage C pour voir et se souvenir de la partie 3 Appelez le langage C depuis Python (argument) c = a + b
Extension Python C / C ++: transmettre une partie des données à Python en tant que np.array (set stride)
Un mémo qui a fait un tutoriel pour exécuter python sur heroku
Comment utiliser la bibliothèque C en Python
Essayez de résoudre le problème de l'héritage de classe Python
Remarques sur la personnalisation de la classe de liste de dict
Je veux faire un jeu avec Python
Copiez la liste en Python
Comment générer un objet Python à partir de JSON
Essayez de créer un code de "décryptage" en Python
Python: préparez un sérialiseur pour l'instance de classe:
Introduction à Python avec Atom (en route)
Enregistrer l'objet dans un fichier avec pickle
Essayez de créer un groupe de dièdre avec Python
amateur python tente de résumer la liste ②
Je veux créer du code C ++ à partir de code Python!
[Python] Lancer un message sur le canal Slack
J'ai fait un peu de recherche sur la classe
Explication de base de Lark (faites un gars comme une coquille avec Python, Lark)
[Python] Vous pouvez enregistrer un objet dans un fichier en utilisant le module pickle.
Comment passer des arguments lors de l'appel d'un script python depuis Blender sur la ligne de commande
Faisons un saut dans l'industrie manufacturière en utilisant le Web en plus de Python
Ne prenez pas une instance d'une classe d'exception Python directement comme argument de la classe d'exception!