Partager via


Créer une extension C++ pour Python dans Visual Studio

Dans cet article, vous créez un module d’extension C++ pour CPython pour calculer une tangente hyperbolique et l’appeler à partir du code Python. La routine est implémentée en premier dans Python pour illustrer le gain de performances relatif de l’implémentation de la même routine en C++.

Les modules de code écrits en C++ (ou C) sont couramment utilisés pour étendre les fonctionnalités d’un interpréteur Python. Il existe trois types principaux de modules d’extension :

  • Modules accélérateurs : activez les performances accélérées. Étant donné que Python est un langage interprété, vous pouvez écrire un module accélérateur en C++ pour obtenir des performances plus élevées.
  • Modules wrapper : exposez des interfaces C/C++ existantes au code Python ou exposez une API de type Python plus facile à utiliser à partir de Python.
  • Modules d’accès système de bas niveau : créez des modules d’accès système pour atteindre des fonctionnalités de niveau inférieur du CPython runtime, du système d’exploitation ou du matériel sous-jacent.

Cet article montre deux façons de rendre un module d’extension C++ disponible pour Python :

  • Utilisez les extensions standard CPython , comme décrit dans la documentation Python.
  • Utilisez PyBind11, que nous vous recommandons pour C++11 en raison de sa simplicité. Pour garantir la compatibilité, vérifiez que vous utilisez l’une des versions les plus récentes de Python.

L’exemple terminé pour cette procédure pas à pas est disponible sur GitHub sur python-samples-vs-cpp-extension.

Conditions préalables

  • Visual Studio 2017 ou version ultérieure, avec la charge de travail de développement Python installée. La charge de travail inclut les outils de développement natifs Python, qui ajoutent la charge de travail C++ et les ensembles d’outils nécessaires pour les extensions natives.

    Capture d’écran d’une liste des options de développement Python, mettant en évidence l’option outils de développement natifs Python.

    Pour plus d’informations sur les options d’installation, consultez Installer la prise en charge de Python pour Visual Studio.

    Remarque

    Lorsque vous installez la charge de travail des applications de science des données et d’applications analytiques , Python et l’option outils de développement natifs Python sont installées par défaut.

  • Si vous installez Python séparément, veillez à sélectionner Télécharger les symboles de débogage sous Options avancées dans le programme d’installation de Python. Cette option est nécessaire pour utiliser le débogage en mode mixte entre votre code Python et le code natif.

Créer l’application Python

Suivez ces étapes pour créer l’application Python.

  1. Créez un projet Python dans Visual Studio en sélectionnant Nouveau>>.

  2. Dans la fenêtre de dialogue Créer un projet, recherchez python. Sélectionnez le modèle d’application Python , puis sélectionnez Suivant.

  3. Entrez un nom de projet et un emplacement, puis sélectionnez Créer.

    Visual Studio crée le nouveau projet. Le projet s’ouvre dans l’Explorateur de solutions et le fichier projet (.py) s’ouvre dans l’éditeur de code.

  4. Dans le fichier .py , collez le code suivant. Pour découvrir certaines des fonctionnalités d’édition Python, essayez d’entrer le code manuellement.

    Ce code calcule une tangente hyperbolique sans utiliser la bibliothèque mathématique, et c’est ce que vous accélérez ultérieurement avec les extensions natives Python.

    Conseil / Astuce

    Écrivez votre code en Python pur avant de le réécrire en C++. De cette façon, vous pouvez vérifier plus facilement que votre code Python natif est correct.

    from random import random
    from time import perf_counter
    
    # Change the value of COUNT according to the speed of your computer.
    # The value should enable the benchmark to complete in approximately 2 seconds.
    COUNT = 500000
    DATA = [(random() - 0.5) * 3 for _ in range(COUNT)]
    
    e = 2.7182818284590452353602874713527
    
    def sinh(x):
        return (1 - (e ** (-2 * x))) / (2 * (e ** -x))
    
    def cosh(x):
        return (1 + (e ** (-2 * x))) / (2 * (e ** -x))
    
    def tanh(x):
        tanh_x = sinh(x) / cosh(x)
        return tanh_x
    
    def test(fn, name):
        start = perf_counter()
        result = fn(DATA)
        duration = perf_counter() - start
        print('{} took {:.3f} seconds\n\n'.format(name, duration))
    
        for d in result:
            assert -1 <= d <= 1, " incorrect values"
    
    if __name__ == "__main__":
        print('Running benchmarks with COUNT = {}'.format(COUNT))
    
        test(lambda d: [tanh(x) for x in d], '[tanh(x) for x in d] (Python implementation)')
    
  5. Exécutez le programme en sélectionnant Démarrer>sans débogage ou sélectionnez le raccourci clavier Ctrl+F5.

    Une fenêtre de commande s’ouvre pour afficher la sortie du programme.

  6. Dans la sortie, notez le temps signalé pour le processus de benchmark.

    Pour cette procédure pas à pas, le processus de benchmark doit prendre environ 2 secondes.

  7. Si nécessaire, ajustez la valeur de la COUNT variable dans le code pour permettre au benchmark de se terminer en environ 2 secondes sur votre ordinateur.

  8. Réexécutez le programme et confirmez que la valeur modifiée COUNT produit le benchmark en environ 2 secondes.

Conseil / Astuce

Lorsque vous exécutez des benchmarks, utilisez toujours l'option Démarrer sans débogage>sans débogage. Cette méthode permet d’éviter la surcharge qui peut s’effectuer lorsque vous exécutez le code dans le débogueur Visual Studio.

Créer les projets C++ principaux

Suivez ces étapes pour créer deux projets C++ identiques, superfastcode et superfastcode2. Plus tard, vous utilisez une approche différente dans chaque projet pour exposer le code C++ à Python.

  1. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le nom de la solution, puis sélectionnez Ajouter>un nouveau projet.

    Une solution Visual Studio peut contenir à la fois des projets Python et C++, qui constituent l’un des avantages de l’utilisation de Visual Studio pour le développement Python.

  2. Dans la boîte de dialogue Ajouter un nouveau projet , définissez le filtre de langue sur C++, puis entrez vide dans la zone de recherche .

  3. Dans la liste des résultats du modèle de projet, sélectionnez Projet vide, puis Sélectionnez Suivant.

  4. Dans la boîte de dialogue Configurer votre nouveau projet , entrez le nom du projet :

    • Pour le premier projet, entrez le nom superfastcode.
    • Pour le deuxième projet, entrez le nom superfastcode2.
  5. Cliquez sur Créer.

Veillez à répéter ces étapes et à créer deux projets.

Conseil / Astuce

Une autre approche est disponible lorsque les outils de développement natifs Python sont installés dans Visual Studio. Vous pouvez commencer par le modèle de module d’extension Python , qui pré-termine la plupart des étapes décrites dans cet article.

Pour la procédure pas à pas de cet article, en commençant par un projet vide, vous pouvez montrer comment générer le module d’extension étape par étape. Après avoir compris le processus, vous pouvez utiliser le modèle de remplacement pour gagner du temps lorsque vous écrivez vos propres extensions.

Ajouter un fichier C++ au projet

Ensuite, ajoutez un fichier C++ à chaque projet.

  1. Dans l’Explorateur de solutions, développez le projet, cliquez avec le bouton droit sur le nœud Fichiers sources , puis sélectionnez Ajouter>un nouvel élément.

  2. Dans la liste des modèles de fichiers, sélectionnez Fichier C++ (.cpp).

  3. Entrez le nom du fichier en tant que module.cpp, puis sélectionnez Ajouter.

    Important

    Vérifiez que le nom de fichier inclut l’extension .cpp . Visual Studio recherche un fichier avec l’extension .cpp pour activer l’affichage des pages de propriétés du projet C++.

  4. Dans la barre d’outils, développez le menu déroulant Configuration et sélectionnez votre type de configuration cible :

    Capture d’écran montrant comment définir le type de configuration cible pour le projet C++ dans Visual Studio.

    • Pour un runtime Python 64 bits, activez la configuration x64 .
    • Pour un runtime Python 32 bits, activez la configuration Win32 .

Veillez à répéter ces étapes pour les deux projets.

Configurer les propriétés du projet

Avant d’ajouter du code aux nouveaux fichiers C++, configurez les propriétés de chaque projet de module C++ et testez les configurations pour vous assurer que tout fonctionne.

Vous devez définir les propriétés du projet pour les configurations de build de débogage et de mise en production de chaque module.

  1. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le projet de module C++ (superfastcode ou superfastcode2), puis sélectionnez Propriétés.

  2. Configurez les propriétés de la build de débogage du module, puis configurez les mêmes propriétés pour la build de mise en production :

    En haut de la boîte de dialogue Pages de propriétés du projet, configurez les options de configuration de fichier suivantes :

    Capture d’écran montrant comment définir les options de génération et de plateforme du projet pour le fichier C++ dans Visual Studio.

    1. Pour la configuration, sélectionnez Déboguer ou Libérer. (Vous pouvez voir ces options avec le préfixe Actif .)

    2. Pour la plateforme, sélectionnez Active (x64) ou Active (Win32) en fonction de votre sélection à l’étape précédente.

      Remarque

      Lorsque vous créez vos propres projets, vous devez configurer les configurations de débogage et de mise en production séparément, en fonction de vos besoins spécifiques en matière de scénario. Dans cet exercice, vous définissez les configurations pour utiliser une build de mise en production de CPython. Cette configuration désactive certaines fonctionnalités de débogage du runtime C++, notamment les assertions. L’utilisation des fichiers binaires de débogage CPython (python_d.exe) nécessite différents paramètres.

    3. Définissez d’autres propriétés de projet comme décrit dans le tableau suivant.

      Pour modifier une valeur de propriété, entrez une valeur dans le champ de propriété. Pour certains champs, vous pouvez sélectionner la valeur actuelle pour développer un menu déroulant de choix ou ouvrir une boîte de dialogue pour vous aider à définir la valeur.

      Après avoir mis à jour les valeurs d’un onglet, sélectionnez Appliquer avant de basculer vers un autre onglet. Cette action permet de garantir que vos modifications restent.

      Onglet et section Propriété Valeur
      Propriétés> de configurationGénéralités Nom de la cible Spécifiez le nom du module pour y faire référence depuis Python dans from...import des instructions, telles que superfastcode. Vous utilisez ce même nom dans le code C++ lorsque vous définissez le module pour Python. Pour utiliser le nom du projet comme nom de module, conservez la valeur par défaut $<ProjectName>. Pour python_d.exe, ajoutez _d à la fin du nom.
      Type de configuration Bibliothèque dynamique (.dll)
      Propriétés> de configurationAvancé Extension de fichier cible .pyd (module d’extension Python)
      C/C++>Généralités Répertoires d'inclusion supplémentaires Ajoutez le dossier Include Python en fonction de votre installation (par exemple, c :\Python36\include).
      C/C++>Préprocesseur Définitions de préprocesseur S’il est présent, remplacez la valeur _DEBUG par NDEBUG pour qu’elle corresponde à la version non de débogage de CPython. Lorsque vous utilisez python_d.exe, laissez cette valeur inchangée.
      C/C++>Génération de code Bibliothèque Runtime DLL multithread (/MD) pour s'aligner sur la version stable (non-debug) de CPython. Lorsque vous utilisez python_d.exe, laissez cette valeur comme DLL de débogage multithread (/MDd).
      Vérifications du runtime de base Par défaut
      Éditeur de liens>Généralités Répertoires de bibliothèque supplémentaires Ajoutez le dossier Libs Python qui contient des fichiers .lib , selon les besoins de votre installation (par exemple, c :\Python36\libs). Veillez à pointer vers le dossier libs qui contient des fichiers .lib , et non le dossier Lib qui contient des fichiers .py .

      Important

      Si l’onglet C/C++ n’est pas affiché en tant qu’option pour les propriétés du projet, le projet ne contient aucun fichier de code que Visual Studio identifie comme fichiers sources C/C++. Cette condition peut se produire si vous créez un fichier source sans extension de fichier .c ou .cpp .

      Si vous avez entré accidentellement module.coo au lieu de module.cpp lorsque vous avez créé le fichier C++, Visual Studio crée le fichier, mais ne définit pas le type de fichier sur le compilateur C/C+. Ce type de fichier est nécessaire pour activer la présence de l’onglet propriétés C/C++ dans la boîte de dialogue propriétés du projet. L’identification incorrecte reste même si vous renommez le fichier de code avec une extension de fichier .cpp .

      Pour définir correctement le type de fichier de code, dans l’Explorateur de solutions, cliquez avec le bouton droit sur le fichier de code et sélectionnez Propriétés. Pour le type d’élément, sélectionnez le compilateur C/C++.

    4. Après avoir mis à jour toutes les propriétés, sélectionnez OK.

    Répétez les étapes de l’autre configuration de build.

  3. Testez votre configuration actuelle. Répétez les étapes suivantes pour les builds de débogage et de mise en production des deux projets C++.

    1. Dans la barre d’outils Visual Studio, définissez la configuration de build sur Débogage ou Mise en production :

      Capture d’écran montrant comment définir la configuration de build pour le projet C++ dans Visual Studio.

    2. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le projet C++, puis sélectionnez Générer.

      Les fichiers .pyd se trouvent dans le dossier solution, sous Débogage et Release, et non dans le dossier du projet C++ lui-même.

Ajouter du code et tester la configuration

Vous êtes maintenant prêt à ajouter du code à vos fichiers C++ et à tester la build de mise en production .

  1. Pour le projet C++ superfastcode , ouvrez le fichier module.cpp dans l’éditeur de code.

  2. Dans le fichier module.cpp , collez le code suivant :

    #include <Windows.h>
    #include <cmath>
    
    const double e = 2.7182818284590452353602874713527;
    
    double sinh_impl(double x) {
        return (1 - pow(e, (-2 * x))) / (2 * pow(e, -x));
    }
    
    double cosh_impl(double x) {
        return (1 + pow(e, (-2 * x))) / (2 * pow(e, -x));
    }
    
    double tanh_impl(double x) {
        return sinh_impl(x) / cosh_impl(x);
    }
    
  3. Enregistrez vos modifications.

  4. Générez la configuration de mise en production du projet C++ pour confirmer que votre code est correct.

Répétez les étapes permettant d’ajouter du code au fichier C++ pour le projet superfastcode2 et de tester la build de mise en production .

Convertir des projets C++ en extensions Python

Pour rendre la DLL C++ une extension pour Python, vous devez d’abord modifier les méthodes exportées pour interagir avec les types Python. Ensuite, ajoutez une fonction pour exporter le module, ainsi que des définitions pour les méthodes du module.

Les sections suivantes montrent comment créer les extensions à l’aide des extensions CPython et PyBind11. Le projet superfasctcode utilise les extensions CPython et le projet superfasctcode2 implémente PyBind11.

Utiliser des extensions CPython

Pour plus d’informations sur le code présenté dans cette section, consultez le manuel de référence de l’API Python/C, en particulier la page Objets de module . Lorsque vous passez en revue le contenu de référence, veillez à sélectionner votre version de Python dans la liste déroulante en haut à droite.

  1. Pour le projet C++ superfastcode , ouvrez le fichier module.cpp dans l’éditeur de code.

  2. Ajoutez une instruction en haut du fichier module.cpp pour inclure le fichier d’en-tête Python.h :

    #include <Python.h>
    
  3. Remplacez le code de méthode tanh_impl pour accepter et retourner des types Python (autrement dit, a PyObject*) :

    PyObject* tanh_impl(PyObject* /* unused module reference */, PyObject* o) {
        double x = PyFloat_AsDouble(o);
        double tanh_x = sinh_impl(x) / cosh_impl(x);
        return PyFloat_FromDouble(tanh_x);
    }
    
  4. À la fin du fichier, ajoutez une structure pour définir comment présenter la fonction C++ tanh_impl à Python :

    static PyMethodDef superfastcode_methods[] = {
        // The first property is the name exposed to Python, fast_tanh
        // The second is the C++ function with the implementation
        // METH_O means it takes a single PyObject argument
        { "fast_tanh", (PyCFunction)tanh_impl, METH_O, nullptr },
    
        // Terminate the array with an object containing nulls
        { nullptr, nullptr, 0, nullptr }
    };
    
  5. Ajoutez une autre structure pour définir comment faire référence au module dans votre code Python, en particulier lorsque vous utilisez l’instruction from...import .

    Le nom importé dans ce code doit correspondre à la valeur dans les Propriétés de configuration>Général>Nom cible.

    Dans l’exemple suivant, le "superfastcode" nom signifie que vous pouvez utiliser l’instruction from superfastcode import fast_tanh en Python, car fast_tanh elle est définie dans superfastcode_methods. Les noms de fichiers internes au projet C++, tels que module.cpp, sont inconséquents.

    static PyModuleDef superfastcode_module = {
        PyModuleDef_HEAD_INIT,
        "superfastcode",                        // Module name to use with Python import statements
        "Provides some functions, but faster",  // Module description
        0,
        superfastcode_methods                   // Structure that defines the methods of the module
    };
    
  6. Ajoutez une méthode que Python appelle lorsqu’il charge le module. Le nom de la méthode doit être PyInit_<module-name>, où <le nom du> module correspond exactement à la propriétéNom cible> des > de configuration du projet C++. Autrement dit, le nom de la méthode correspond au nom de fichier du fichier .pyd généré par le projet.

    PyMODINIT_FUNC PyInit_superfastcode() {
        return PyModule_Create(&superfastcode_module);
    }
    
  7. Générez le projet C++ et vérifiez votre code. Si vous rencontrez des erreurs, consultez la section « Résoudre les erreurs de compilation ».

Utiliser PyBind11

Si vous effectuez les étapes de la section précédente pour le projet superfastcode , vous remarquerez peut-être que l’exercice nécessite du code réutilisable pour créer les structures de module pour les extensions C++ CPython. Dans cet exercice, vous découvrez que PyBind11 simplifie le processus de codage. Vous utilisez des macros dans un fichier d’en-tête C++ pour obtenir le même résultat, mais avec beaucoup moins de code. Toutefois, des étapes supplémentaires sont nécessaires pour vous assurer que Visual Studio peut localiser les bibliothèques PyBind11 et inclure des fichiers. Pour plus d’informations sur le code de cette section, consultez les principes de base de PyBind11.

Installer PyBind11

La première étape consiste à installer PyBind11 dans la configuration de votre projet. Dans cet exercice, vous utilisez la fenêtre Développeur PowerShell .

  1. Ouvrez la fenêtre Outils>ligne de commande>PowerShell du développeur.

  2. Dans la fenêtre Développeur PowerShell , installez PyBind11 à l’aide de la commande pip install pybind11 pip ou py -m pip install pybind11.

    Visual Studio installe PyBind11 et ses packages dépendants.

Ajouter des chemins PyBind11 au projet

Après l’installation de PyBind11, vous devez ajouter les chemins PyBind11 à la propriété Autres répertoires Include pour le projet.

  1. Dans Developer PowerShell , exécutez la commande python -m pybind11 --includes ou py -m pybind11 --includes.

    Cette action imprime la liste des chemins PyBind11 que vous devez ajouter aux propriétés de votre projet.

  2. Mettez en surbrillance la liste des chemins d’accès dans la fenêtre et sélectionnez Copier (double page) dans la barre d’outils de la fenêtre.

    Capture d’écran montrant comment mettre en surbrillance et copier la liste des chemins d’accès à partir de la fenêtre Développeur PowerShell dans Visual Studio.

    La liste des chemins concaténés est ajoutée à votre presse-papiers.

  3. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le projet superfastcode2 , puis sélectionnez Propriétés.

  4. En haut de la boîte de dialogue Pages de propriétés , pour le champ Configuration , sélectionnez Mise en production. (Vous pouvez voir cette option avec le préfixe Actif .)

  5. Dans la boîte de dialogue, sous l’onglet C/C++>Général , développez le menu déroulant de la propriété Répertoires Include supplémentaires , puis sélectionnez Modifier.

  6. Dans la boîte de dialogue contextuelle, ajoutez la liste des chemins copiés :

    Répétez ces étapes pour chaque chemin d’accès dans la liste concaténée copiée à partir de la fenêtre Développeur PowerShell :

    1. Sélectionnez Nouvelle ligne (dossier avec symbole plus) dans la barre d’outils de la boîte de dialogue contextuelle.

      Capture d’écran montrant comment ajouter un chemin PyBind11 à la propriété Autres répertoires Include.

      Visual Studio ajoute une ligne vide en haut de la liste des chemins d’accès et positionne le curseur d’insertion au début.

    2. Collez le chemin PyBind11 dans la ligne vide.

      Vous pouvez également sélectionner d’autres options (...) et utiliser une boîte de dialogue de l’Explorateur de fichiers contextuels pour accéder à l’emplacement du chemin d’accès.

      Important

      • Si le chemin contient le préfixe -I, supprimez le préfixe du chemin.
      • Pour que Visual Studio reconnaisse un chemin, le chemin doit se trouver sur une ligne distincte.

      Après avoir ajouté un nouveau chemin d’accès, Visual Studio affiche le chemin confirmé dans le champ Valeur évaluée .

  7. Sélectionnez OK pour quitter la boîte de dialogue contextuelle.

  8. En haut de la boîte de dialogue Pages de propriétés, pointez sur la valeur de la propriété Répertoires Include supplémentaires et vérifiez que les chemins PyBind11 sont présents.

  9. Sélectionnez OK pour appliquer les modifications de propriété.

Mettre à jour le fichier module.cpp

La dernière étape consiste à ajouter le fichier d’en-tête PyBind11 et le code macro au fichier C++ du projet.

  1. Pour le projet C++ superfastcode2 , ouvrez le fichier module.cpp dans l’éditeur de code.

  2. Ajoutez une instruction en haut du fichier module.cpp pour inclure le fichier d’en-tête pybind11.h :

    #include <pybind11/pybind11.h>
    
  3. À la fin du fichier module.cpp , ajoutez du code pour la PYBIND11_MODULE macro pour définir le point d’entrée à la fonction C++ :

    namespace py = pybind11;
    
    PYBIND11_MODULE(superfastcode2, m) {
        m.def("fast_tanh2", &tanh_impl, R"pbdoc(
            Compute a hyperbolic tangent of a single argument expressed in radians.
        )pbdoc");
    
    #ifdef VERSION_INFO
        m.attr("__version__") = VERSION_INFO;
    #else
        m.attr("__version__") = "dev";
    #endif
    }
    
  4. Générez le projet C++ et vérifiez votre code. Si vous rencontrez des erreurs, consultez la section suivante, résoudre les erreurs de compilation.

Résoudre les erreurs de compilation

Passez en revue les sections suivantes pour connaître les problèmes possibles qui peuvent entraîner l’échec de la génération du module C++.

Erreur : Impossible de localiser le fichier d’en-tête

Visual Studio retourne un message d’erreur tel que E1696 : Impossible d’ouvrir le fichier open source « Python.h » ou C1083 : Impossible d’ouvrir le fichier include : « Python.h » : Aucun fichier ou répertoire de ce type.

Cette erreur indique que le compilateur ne peut pas localiser un fichier d’en-tête (.h) requis pour votre projet.

  • Pour le projet superfastcode, vérifiez que la propriété de projetRépertoires Include supplémentaires>> contient le chemin d’accès au dossier Include de votre installation Python. Passez en revue les étapes de configuration des propriétés du projet.

  • Pour le projet superfastcode2 , vérifiez que la même propriété de projet contient le chemin d’accès au dossier Include de votre installation PyBind11. Passez en revue les étapes pour ajouter les chemins d'Ad PyBind au projet.

Pour plus d’informations sur l’accès à vos informations de configuration d’installation Python, consultez la documentation Python.

Erreur : Impossible de localiser les bibliothèques Python

Visual Studio retourne une erreur indiquant que le compilateur ne peut pas localiser les fichiers de bibliothèque (DLL) requis pour votre projet.

  • Pour le projet C++ (superfastcode ou superfastcode2), vérifiez que la propriétéRépertoires de bibliothèque supplémentaires>> contient le chemin d’accès au dossier libs de votre installation Python. Passez en revue les étapes de configuration des propriétés du projet.

Pour plus d’informations sur l’accès à vos informations de configuration d’installation Python, consultez la documentation Python.

Visual Studio signale des erreurs d’éditeur de liens liées à la configuration de l’architecture cible pour votre projet, comme x64 ou Win32.

  • Pour le projet C++ (superfastcode ou superfastcode2 ), modifiez la configuration cible pour qu’elle corresponde à votre installation python. Par exemple, si votre configuration cible de projet C++ est Win32, mais que votre installation Python est 64 bits, remplacez la configuration cible du projet C++ par x64.

Tester le code et comparer les résultats

Maintenant que vous disposez des DLL structurées en tant qu’extensions Python, vous pouvez les référencer à partir du projet Python, importer les modules et utiliser leurs méthodes.

Rendre votre DLL disponible pour Python

Vous pouvez rendre votre DLL disponible pour Python de plusieurs façons. Voici deux options à prendre en compte :

Si votre projet Python et votre projet C++ se trouvent dans la même solution, vous pouvez utiliser l’approche suivante :

  1. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le nœud Références dans votre projet Python, puis sélectionnez Ajouter une référence.

    Veillez à effectuer cette action pour votre projet Python, et non pour votre projet C++.

  2. Dans la boîte de dialogue Ajouter une référence , développez l’onglet Projets .

  3. Cochez les cases pour les projets superfastcode et superfastcode2 , puis sélectionnez OK.

    Capture d’écran montrant comment ajouter une référence au projet de code super rapide dans Visual Studio.

Une autre approche consiste à installer le module d’extension C++ dans votre environnement Python. Cette méthode rend le module disponible pour d’autres projets Python. Pour plus d’informations, consultez la documentation du projet setuptools.

Effectuez les étapes suivantes pour installer le module d’extension C++ dans votre environnement Python :

  1. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur votre projet C++, puis sélectionnez Ajouter>un nouvel élément.

  2. Dans la liste des modèles de fichiers, sélectionnez Fichier C++ (.cpp).

  3. Entrez le nom du fichier en tant que setup.py, puis sélectionnez Ajouter.

    Veillez à entrer le nom de fichier avec l’extension Python (.py). Visual Studio reconnaît le fichier en tant que code Python malgré l’utilisation du modèle de fichier C++.

    Visual Studio ouvre le nouveau fichier dans l’éditeur de code.

  4. Collez le code suivant dans le nouveau fichier. Choisissez la version de code qui correspond à votre méthode d’extension :

    • Extensions CPython (projet superfastcode ) :

      from setuptools import setup, Extension
      
      sfc_module = Extension('superfastcode', sources = ['module.cpp'])
      
      setup(
          name='superfastcode',
          version='1.0',
          description='Python Package with superfastcode C++ extension',
          ext_modules=[sfc_module]
      )
      
    • PyBind11 (projet superfastcode2 ) :

      from setuptools import setup, Extension
      import pybind11
      
      cpp_args = ['-std=c++11', '-stdlib=libc++', '-mmacosx-version-min=10.7']
      
      sfc_module = Extension(
          'superfastcode2',
          sources=['module.cpp'],
          include_dirs=[pybind11.get_include()],
          language='c++',
          extra_compile_args=cpp_args,
      )
      
      setup(
          name='superfastcode2',
          version='1.0',
          description='Python package with superfastcode2 C++ extension (PyBind11)',
          ext_modules=[sfc_module],
      )
      
  5. Dans le projet C++, créez un deuxième fichier nommé pyproject.toml et collez le code suivant :

    [build-system]
    requires = ["setuptools", "wheel", "pybind11"]
    build-backend = "setuptools.build_meta"
    

    Le fichier TOML (.toml) utilise le format De langage clair et minimal de Tom pour les fichiers de configuration.

  6. Pour générer l’extension, cliquez avec le bouton droit sur le nom de fichier pyproject.toml sous l’onglet de la fenêtre de code, puis sélectionnez Copier le chemin complet.

    Capture d’écran montrant comment copier le chemin complet du fichier py project toml dans Visual Studio.

    Vous supprimez le nom pyproject.toml du chemin avant de l’utiliser.

  7. Dans l’Explorateur de solutions, développez le nœud Environnements Python pour la solution.

  8. Cliquez avec le bouton droit sur l’environnement Python actif (affiché en gras), puis sélectionnez Gérer les packages Python.

    Le volet Environnements Python s’ouvre.

    Si le package nécessaire est déjà installé, vous pouvez le voir répertorié dans ce volet.

    • Avant de continuer, sélectionnez le X en regard du nom du package pour le désinstaller.

    Capture d’écran montrant comment désinstaller un package dans le volet Environnements Python.

  9. Dans la zone de recherche du volet Environnements Python , collez le chemin d’accès copié et supprimez le nom de fichier pyproject.toml à partir de la fin du chemin.

    Capture d’écran montrant comment entrer le chemin d’accès dans le volet Environnements Python pour installer le module d’extension.

  10. Sélectionnez Entrée pour installer le module à partir de l’emplacement du chemin d’accès copié.

    Conseil / Astuce

    Si l’installation échoue en raison d’une erreur d’autorisation, ajoutez l’argument --user à la fin de la commande et réessayez l’installation.

Appeler la DLL à partir de Python

Après avoir mis la DLL à la disposition de Python, comme décrit dans la section précédente, vous êtes prêt à appeler les fonctions superfastcode.fast_tanh et superfastcode2.fast_tanh2 à partir de Python. Vous pouvez ensuite comparer les performances de la fonction à l’implémentation Python.

Procédez comme suit pour appeler la DLL du module d’extension à partir de Python :

  1. Ouvrez le fichier .py de votre projet Python dans l’éditeur de code.

  2. À la fin du fichier, ajoutez le code suivant pour appeler les méthodes exportées à partir des DLL et afficher leur sortie :

    from superfastcode import fast_tanh
    test(lambda d: [fast_tanh(x) for x in d], '[fast_tanh(x) for x in d] (CPython C++ extension)')
    
    from superfastcode2 import fast_tanh2
    test(lambda d: [fast_tanh2(x) for x in d], '[fast_tanh2(x) for x in d] (PyBind11 C++ extension)')
    
  3. Exécutez le programme Python en sélectionnant Démarrer>sans débogage ou en utilisant le raccourci clavier Ctrl+F5.

    Remarque

    Si la commande Démarrer sans débogage n’est pas disponible, dans l’Explorateur de solutions, cliquez avec le bouton droit sur le projet Python, puis sélectionnez Définir comme projet de démarrage.

    Lorsque le programme s’exécute, notez que les routines C++ s’exécutent environ 5 à 20 fois plus rapidement que l’implémentation python.

    Voici un exemple de sortie de programme classique :

    Running benchmarks with COUNT = 500000
    [tanh(x) for x in d] (Python implementation) took 0.758 seconds
    
    [fast_tanh(x) for x in d] (CPython C++ extension) took 0.076 seconds
    
    [fast_tanh2(x) for x in d] (PyBind11 C++ extension) took 0.204 seconds
    
  4. Essayez d’augmenter la variable afin que les COUNT différences de temps soient plus prononcées.

    Une build de débogage du module C++ s’exécute également plus lentement qu’une build de mise en production , car la build de débogage est moins optimisée et contient diverses vérifications d’erreur. Essayez de basculer entre les configurations de build pour la comparaison, mais n’oubliez pas de mettre à jour les propriétés que vous avez définies précédemment pour la configuration de la version.

Traiter la vitesse et la surcharge du processus

Dans la sortie, vous remarquerez peut-être que l’extension PyBind11 n’est pas aussi rapide que l’extension CPython, bien qu’elle soit plus rapide que l’implémentation De Python pure. La principale raison de la différence est due à l’utilisation de l’indicateur de METH_O. Cet indicateur ne prend pas en charge plusieurs paramètres, noms de paramètres ou arguments de mots clés. PyBind11 génère du code légèrement plus complexe pour fournir une interface de type Python aux appelants. Étant donné que le code de test appelle la fonction 500 000 fois, les résultats peuvent considérablement amplifier la surcharge.

Vous pouvez réduire davantage la surcharge en déplaçant la for boucle dans le code Python natif. Cette approche implique l’utilisation du protocole itérateur (ou du type PyBind11 py::iterable pour le paramètre de fonction) pour traiter chaque élément. La suppression des transitions répétées entre Python et C++ est un moyen efficace de réduire le temps nécessaire pour traiter la séquence.

Résoudre les erreurs d’importation

Si vous recevez un message ImportError lorsque vous essayez d’importer votre module, vous pouvez y remédier de l’une des manières suivantes :

  • Lorsque vous générez une référence de projet, vérifiez que vos propriétés de projet C++ correspondent à l’environnement Python activé pour votre projet Python. Vérifiez que les mêmes emplacements de dossier sont utilisés pour les fichiers Include (.h) et Bibliothèque (DLL).

  • Vérifiez que votre fichier de sortie est correctement nommé, tel que superfastcode.pyd. Un nom ou une extension incorrect empêche l’importation du fichier nécessaire.

  • Si vous installez votre module à l’aide du fichier setup.py , veillez à exécuter la pip commande dans l’environnement Python activé pour votre projet Python. Lorsque vous développez l’environnement Python actif pour votre projet dans l’Explorateur de solutions, vous devez voir une entrée pour le projet C++, tel que le superfastcode.

Déboguer le code C++

Visual Studio prend en charge le débogage du code Python et C++ ensemble. Les étapes suivantes illustrent le processus de débogage du projet C++ superfastcode , mais le processus est le même pour le projet superfastcode2 .

  1. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le projet Python, puis sélectionnez Propriétés.

  2. Dans le volet Propriétés, sélectionnez l’onglet Débogage, puis sélectionnez l’option Activer> ledébogage du code natif.

    Conseil / Astuce

    Lorsque vous activez le débogage de code natif, la fenêtre de sortie Python peut se fermer immédiatement une fois que le programme est terminé sans pause et sans afficher l’invite Appuyez sur n’importe quelle touche pour continuer. Pour forcer la pause et l’invite après avoir activé le débogage du code natif, ajoutez l’argument -i au champ Exécuter>les arguments de l’interpréteur sous l’onglet Débogage . Cet argument place l’interpréteur Python en mode interactif après l’exécution du code. Le programme attend que vous deviez sélectionner Ctrl+Z+Entrée pour fermer la fenêtre. Une autre approche consiste à ajouter les instructions import os et os.system("pause") à la fin de votre programme Python. Ce code duplique l’invite de pause d’origine.

  3. SélectionnezEnregistrer un > (ou Ctrl+S) pour enregistrer les modifications de propriété.

  4. Dans la barre d’outils Visual Studio, définissez la configuration de build sur Débogage.

  5. Étant donné que le code prend généralement plus de temps à s’exécuter dans le débogueur, vous pouvez modifier la COUNT variable dans votre projet Python .py fichier en une valeur qui est environ cinq fois plus petite que la valeur par défaut. Par exemple, remplacez-le de 500000 à100000.

  6. Dans votre code C++, définissez un point d’arrêt sur la première ligne de la tanh_impl méthode.

  7. Démarrez le débogueur en sélectionnant Déboguer>Démarrer le débogage ou en utilisant le raccourci clavier F5.

    Le débogueur s’arrête lorsque le code du point d’arrêt est appelé. Si le point d’arrêt n’est pas atteint, vérifiez que la configuration est définie sur Déboguer et que vous avez enregistré le projet, ce qui ne se produit pas automatiquement lorsque vous démarrez le débogueur.

    Capture d’écran du code C++ qui contient un point d’arrêt dans Visual Studio.

  8. Au point d’arrêt, vous pouvez parcourir le code C++, examiner les variables, et ainsi de suite. Pour plus d’informations sur ces fonctionnalités, consultez Déboguer Python et C++ ensemble.

Approches secondaires

Vous pouvez créer des extensions Python de différentes façons, comme décrit dans le tableau suivant. Les deux premières lignes, CPython et PyBind11, sont abordées dans cet article.

Approche Ancien Utilisateurs représentatifs
Modules d’extension C/C++ pour CPython 1991 bibliothèque standard
PyBind11 (recommandé pour C++) 2015
Cython (recommandé pour C) 2007 gevent, kivy
HPy 2019
mypyc 2017
ctypes 2003 oscrypto
cffi 2013 chiffrement, pypy
LAMPÉE 1996 crfsuite
Boost.Python 2002
cppyy 2017