INF 739 : Concepts Avancés de Programmation

publicité
INF 739 : Concepts avancés de
programmation
Interfaçage entre C++ et Python
Patrick Hubert
Artificial Mind & Movement
Le C++ et Python
Description sommaire des deux langages…
Le langage C++
Conçu par Bjarne Stroustrup en 1983
•
•
•
•
•
Langage compilé avec phase d’édition de liens
Fortement typé
Statique
Performant et rapide, héritage provenant du C
Gestion de la mémoire laissée au programmeur
Le langage Python
Conçu par Guido Van Rossum en 1991
•
•
•
•
•
Langage interprété
Se base sur l’interface plutôt que le type
Dynamique
Moins rapide, car interprété
Gestion de mémoire automagique (Garbage
Collector)
Le développement en C++
Les structures et fonctions sont définies
explicitement dans les fichiers sources
Un cycle comprend habituellement les étapes
suivantes:
1. Édition du code
2. Compilation des sources
3. Éditions des liens
4. Démarrage de l’application et validation
5. Arrêt de l’application et retour a 1.
Le développement en Python
Ce qui à été dit pour le C++ est aussi valide…
Par contre, les structures et fonctions peuvent aussi
être créées ou modifiées alors que l’application
fonctionne
Un cycle peut être réduit aux étapes suivantes:
1. Édition du code
2. Démarrage de l’application et interprétation
3. Modifications et mises-à-jour des structures
existantes dynamiquement, et/ou retour à 1.
Le compilateur C++
• N’est qu’une des composantes requises pour
concevoir une application
• L’éditeur de lien et le débogueur sont deux
autres applications indépendantes requises
• L’application résultante est le quatrième
maillon de la chaîne
L’interpréteur Python
• Est à la fois compilateur, éditeur de liens,
débogueur et l’application résultante
• Il en existe une implémentation C et Java
• On imagine souvent à tort qu’il est un outil
disponible sur ligne de commande. Ce n’est
là qu’une des intégrations possible
L’interpréteur Python
Évaluation visible à l’usager:
• Interface interactive via la ligne de commande
• Interprétation immédiate du code
% python
Python 2.5 (r25:51908, Mar 13 2007, 08:13:14)
[GCC 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
>>> print "Bonjour!"
Bonjour!
>>>
L’interpréteur Python
Évaluation invisible à l’usager:
• Analyse syntaxique et interprétation des modules
• Création dynamique des classes, fonctions, etc.
% python
Python 2.5 (r25:51908, Mar 13 2007, 08:13:14)
[GCC 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import Bibliotheque
>>> print Bibliotheque.Fonction( 'Foobar' )
6
>>>
Comparaison de code
Les langages offrent des bases communes et
des éléments structurels similaires:
• Fonctions
• Classes
• Bibliothèques ou modules
Exemple de fonction C++
#include <string>
namespace Bibliotheque {
size_t Fonction( const std::string& pTexte )
{
return pTexte.length();
}
}
// Ne fonctionne qu’avec des arguments de type
// std::string
Exemple de fonction Python
def Fonction( pTexte ):
# equivalent a len( pTexte )
return pTexte.__len__()
#
#
#
#
#
#
#
#
Fonctionne aussi bien avec un paramètre de type
string qu'une liste, donne '3' dans les 2 cas
Fonction( "abc" ) et # Fonction( [ 1, 2, 3 ] )
'__len__()' est présent dans toutes les interfaces
de séquences Python.
'template <typename tType> size_t Fonction( tType );'
se résout statiquement à la compilation, au contraire
de la version Python qui l'est dynamiquement
Utilisation de bibliothèques en
C++
#include <Bibliotheque.hpp>
#include <iostream>
int main()
{
std::string lString( "abc" );
std::cout << Bibliotheque::Fonction( lString ) << std::endl;
return 0;
}
// S'assurer bien sur de mentionner la
// Bibliothèque lors de l'édition des liens
Utilisation de modules en Python
import Bibliotheque
print Bibliotheque.Fonction( 'abcd' );
Une classe en C++
#include <Bibliotheque.hpp>
#include <string>
struct Parent {};
class Enfant : public Parent
{
std::string mChaine;
public:
Enfant( const std::string& pChaine ) : mChaine( pChaine ) {}
size_t Valeur() const { return Bibliotheque::Fonction( mChaine ); }
};
Une classe en Python
import Bibliotheque
class Parent:
pass
class Enfant( Parent ):
def __init__( self, pChaine ):
self.mChaine = pChaine
def Valeur( self ):
return Bibliotheque.Fonction( self.mChaine )
Métissage des deux langages
Il existe trois façons d’interfacer C++ et Python:
1. Écrire de nouveaux modules pour Python en
C++ (pour des raisons de performances)
2. Intégrer l’interpréteur Python à même une
application (pour exposer de la fonctionnalité
existante, ou même en ajouter)
3. Une combinaison des deux options précédentes
Quels sont les avantages?
• Combiner la vitesse de C++ avec la facilité et la
rapidité de développement en Python
• Pour modifier le code de l’application, il faut
habituellement l’arrêter. De même pour un plug-in
ou une DLL/DSO
• En Python, ce n’est pas le cas. La construction
dynamique des objets permet une modification de
ces derniers sans avoir redémarrer l’application
Considérations importantes
• Le langage C++ est fortement typé
• L’interaction entre Python et le C++ devra
tenir compte de cette contrainte et s’assurer
de la compatibilités des objets et paramètres
• Les outils que nous considérerons pour le
travail devront offrir cette protection.
La couche d’interface entre C++
et Python
• L’interpréteur est implémenté en C
• L’interface peut donc être en C ou C++
• Elle peut être écrite manuellement, ce qui laisse
beaucoup de place à l’erreur.
• Elle peut aussi être écrite a l’aide de classes
utilitaires, ou bien généré à partir d’un IDL
(Interface Definition Language)
• Nous présenterons 3 alternatives: manuelle,
Boost.Python (classes) et SWIG (générateur)
Manuelle
• Demande une bonne connaissance de
l’interface C de Python
• Les erreurs sont très faciles
• Requiert beaucoup de maintenance, pour un
API qui change beaucoup
Manuelle (code 1/2)
#include <python.h>
#include <Bibliotheque.hpp>
static PyObject*
Fonction_imp( PyObject* pSelf, PyObject* pArgs )
{
const char* lChaine = 0;
if( !PyArg_ParseTuple( pArgs, "s", &lChaine ))
return 0;
size_t lResult = Bibliotheque::Fonction( lChaine );
return Py_BuildValue( "i", lResult );
}
Manuelle (code 2/2)
static PyMethodDef ManuelleMethods[] = {
{ "Fonction", Fonction_imp, METH_VARARGS, "" },
{0, 0, 0, 0}
};
PyMODINIT_FUNC
initManuelle()
{
Py_InitModule( "Manuelle", ManuelleMethods );
}
Boost.Python
• Fait partie de la bibliothèque Boost
• Met à notre disposition des templates de classes pour
définir les classes, méthodes et fonctions à exposer vers
Python
• Utilise le ‘Run-Time Type Identification’ (RTTI) pour
générer les interfaces du bon type
• Dépend aussi énormément des algorithmes du compilateur
pour déduire les paramètres de templates.
• Offre des outils pour communiquer avec les objets Python
indigènes
Boost.Python (code)
#include <boost/python.hpp>
using namespace boost::python;
#include <Bibliotheque.hpp>
BOOST_PYTHON_MODULE( Boost )
{
def( "Fonction", Bibliotheque::Fonction );
}
SWIG
• ‘Simplified Wrapper and Interface Generator’
• À partir d’un fichier de définition d’interface créé
par le programmeur, génère du code Python et
C/C++ qui fait le lien entre les deux langages
• Demande une étape de manipulation
supplémentaire, pour la génération du code
intermédiaire.
• Est très rapide et relativement facile a utiliser, tout
en offrant une série de paramétrisations
SWIG (code)
%module Swig
%include "std_string.i"
%{
#include <Bibliotheque.hpp>
using namespace Bibliotheque;
%}
size_t Fonction( const std::string& pTexte );
Expérience personnelle
Exposition de l’API d’un SDK orienté-objet en C++
en Python, le OpenRealitySDK de MotionBuilder
• Correspondance 1 à 1 des deux langages dans 90%
des cas. Pour certaines méthodes spéciales, telle
'operator=‘, nous nous devions de trouver des
alternatives.
• Nous avons choisis Boost.Python
• Le code C++ de Boost.Python était généré à partir
de fichiers XML décrivant les classes C++ de
notre SDK.
Points positifs
• Accélère le cycle de développement de façon
significative
• Permet d’exposer une interface à l’application
auprès d’un plus grand public
• Python ne requiert pas un environnement de
développement (MSDEV, GCC, etc.)
• Permet la création de nouvelles fonctionnalités en
Python exclusivement, sur lesquelles on peut bâtir
un nouvel environnement pour des gens moins
familiers avec la programmation
Points négatifs
• La gestion de la couche d’interface, Boost.Python
ou bien SWIG, peut être onéreuse et ardue.
Surtout si l’API à exposer est complexe et évolue
encore
• Trouver une façon d’automatiser la génération de
la couche d’interface n’est pas facile
• Les temps de compilation de la couche utilisant
Boost.Python sont importants
Points à surveiller
• S’assurer qu’une instance d’objet C++ donnée est
encapsulée par un seul objet Python.
• Certaines méthodes d’objets n’ont pas de correspondance
en Python, tel 'operator=‘
• En portant un SDK C++ on risque d’avoir un API Python
qui laisse transparaître ses origines.
• Modifier les interfaces des objets pour se conformer à ce
qui se fait sur Python
• Ajouter les éléments syntaxiques nécessaire pour éviter
que le code Python ressemble a du C++ (conversion, etc.)
Suggestions
• A moins de n’avoir que quelque fonctions simples
à exposer à Python, ne pas utiliser la méthode
manuelle
• SWIG est la solution la plus facile pour les projets
de moyenne envergure
• Boost.Python est excellent pour interfacer
directement avec Python, en plus d’offrir de bons
outils. Par contre il y a un impact important sur les
temps de compilations
Vos questions ?
•
•
•
•
C++
Python
Performances
Pourquoi le ciel est-il bleu?
Références
• Python:
http://python.org/
• Boost:
http://boost.org/
• Swig:
http://www.swig.org/
Merci!
Commentaires et questions:
[email protected]
Téléchargement