Creación de una extensión de C++ para PythonCreating a C++ extension for Python

Los módulos escritos en C++ (o C) se suelen usar para ampliar las capacidades de un intérprete de Python y para permitir el acceso a funciones de bajo nivel del sistema operativo.Modules written in C++ (or C) are commonly used to extend the capabilities of a Python interpreter as well as to enable access to low-level operating system capabilities. Hay tres tipos principales de módulos:There are three primary types of modules:

  • Módulos de acelerador: dado que Python es un lenguaje interpretado, algunas partes del código pueden escribirse en C++ para un mayor rendimiento.Accelerator modules: because Python is an interpreted language, certain pieces of code can be written in C++ for higher performance.
  • Módulos de contenedor: exponen las interfaces de C o C++ existentes a código de Python o exponen una API más propia de Python que se pueda usar fácilmente con este código.Wrapper modules: expose existing C/C++ interfaces to Python code or expose a more "Pythonic" API that's easy to use from Python.
  • Módulos de acceso al sistema de bajo nivel: creados para tener acceso a características de bajo nivel del tiempo de ejecución de CPython, el sistema operativo o el hardware subyacente.Low-level system access modules: created to access lower-level features of the CPython runtime, the operating system, or the underlying hardware.

Este artículo le guía por la compilación de un módulo de extensión de C++ para CPython que calcula la tangente hiperbólica y realiza una llamada desde el código de Python.This article walks through building a C++ extension module for CPython that computes a hyperbolic tangent and calls it from Python code. Primero, se implementa la rutina en Python para demostrar la mejora relativa del rendimiento de la implementación de la misma rutina en C++.The routine is implemented first in Python to demonstrate the relative performance gain of implementing the same routine in C++.

El enfoque adoptado aquí es el de las extensiones de CPython estándar que se describe en la documentación de Python.The approach taken here is that for standard CPython extensions as described in the Python documentation. Al final de este artículo, en Enfoques alternativos, se describe una comparación entre este y otros medios.A comparison between this and other means is described under alternative approaches at the end of this article.

El ejemplo completo de este tutorial se puede encontrar en python-samples-vs-cpp-extension (GitHub).The completed sample from this walkthrough can be found on python-samples-vs-cpp-extension (GitHub).

Requisitos previosPrerequisites

  • Visual Studio 2017 con las cargas de trabajo Desarrollo para el escritorio con C++ y Desarrollo de Python instaladas con opciones predeterminadas.Visual Studio 2017 with both the Desktop Development with C++ and Python Development workloads installed with default options.
  • En la carga de trabajo Desarrollo de Python, seleccione también el cuadro de la derecha de Herramientas de desarrollo nativo de Python.In the Python Development workload, also select the box on the right for Python native development tools. Esta opción establece la mayor parte de la configuración descrita en este artículo.This option sets up most of the configuration described in this article. (Esta opción también incluye la carga de trabajo de C++ automáticamente).(This option also includes the C++ workload automatically.)

    Selección de la opción Herramientas de desarrollo nativo Python

    Sugerencia

    La instalación de la carga de trabajo Aplicaciones de ciencia de datos y de análisis también incluye Python y la opción Herramientas de desarrollo nativo Python de forma predeterminada.Installing the Data science and analytical applications workload also includes Python and the Python native development tools option by default.

Para obtener más información, vea Installing Python Support for Visual Studio (Instalación de la compatibilidad de Python para Visual Studio), incluido el uso de otras versiones de Visual Studio.For more information, see Installing Python Support for Visual Studio, including using other versions of Visual Studio. Si instala Python por separado, asegúrese de seleccionar Download debugging symbols (Descargar símbolos de depuración) y Download debug binaries (Descargar archivos binarios de depuración) en Opciones avanzadas en el programa de instalación.If you install Python separately, be sure to select Download debugging symbols and Download debug binaries under Advanced Options in the installer. Esta opción le asegura que tendrá disponibles las bibliotecas de depuración necesarias si decide realizar una compilación de depuración.This option ensures that you have the necessary debug libraries available if you choose to do a debug build.

Crear la aplicación de PythonCreate the Python application

  1. Cree un proyecto de Python en Visual Studio. Para ello, seleccione Archivo > Nuevo > Proyecto.Create a new Python project in Visual Studio by selecting File > New > Project. Busque “Python”, seleccione la plantilla Aplicación de Python, dele un nombre, asígnele una ubicación y seleccione Aceptar.Search for "Python", select the Python Application template, give it a suitable name and location, and select OK.

  2. El trabajo con C++ requiere que use un intérprete de Python de 32 bits (se recomienda Python 3.6).Working with C++ requires that you use a 32-bit Python interpreter (Python 3.6 recommended). En la ventana Explorador de soluciones de Visual Studio, expanda el nodo del proyecto y luego expanda el nodo Entornos de Python.In the Solution Explorer window of Visual Studio, expand the project node, then expand the Python Environments node. Si no ve un entorno de 32 bits como el valor predeterminado (ya sea en negrita o con la etiqueta "valor predeterminado global"), siga las instrucciones que figuran en Selección de un entorno y un intérprete de Python para usarlo en un proyecto.If you don't see a 32-bit environment as the default (either in bold, or labeled with "global default"), then follow the instructions on Selecting a Python environment for a project. Si no tiene instalado un intérprete de 32 bits, consulte Instalación de intérpretes de Python.If you don't have a 32-bit interpreter installed, see Installing Python interpreters.

  3. En el archivo .py del proyecto, pegue el código siguiente, que realiza una prueba comparativa del cálculo de una tangente hiperbólica (implementada sin usar la biblioteca matemática para facilitar la comparación).In the project's .py file, paste the following code that benchmarks the computation of a hyperbolic tangent (implemented without using the math library for easier comparison). No dude en escribir el código manualmente para experimentar algunas de las características de edición de Python.Feel free to enter the code manually to experience some of the Python editing features.

    from itertools import islice
    from random import random
    from time import perf_counter
    
    COUNT = 500000  # Change this value depending on the speed of your computer
    DATA = list(islice(iter(lambda: (random() - 0.5) * 3.0, None), 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 sequence_tanh(data):
        '''Applies the hyperbolic tangent function to map all values in
        the sequence to a value between -1.0 and 1.0.
        '''
        result = []
        for x in data:
            result.append(tanh(x))
        return result
    
    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(sequence_tanh, 'sequence_tanh')
    
        test(lambda d: [tanh(x) for x in d], '[tanh(x) for x in d]')
    
  4. Ejecute el programa mediante Depurar > Iniciar sin depurar (Ctrl + F5) para ver los resultados.Run the program using Debug > Start Without Debugging (Ctrl+F5) to see the results. Puede ajustar la variable COUNT para cambiar el tiempo que tardan en ejecutarse las pruebas comparativas.You can adjust the COUNT variable to change how long the benchmarks take to run. Para los fines de este tutorial, establezca el número para que cada prueba comparativa tarde aproximadamente dos segundos.For the purposes of this walkthrough, set the count so that each benchmark takes around two seconds.

Crear el proyecto de C++ principalCreate the core C++ project

  1. Haga clic con el botón derecho en la solución en el Explorador de soluciones y seleccione Agregar > Nuevo proyecto…. Una solución de Visual Studio puede contener proyectos de Python y C++ juntos (que es una de las ventajas de utilizar Visual Studio para Python).Right-click the solution in Solution Explorer and select Add > New Project.... A Visual Studio solution can contain both Python and C++ projects together (which is one of the advantages of using Visual Studio for Python).

  2. Busque "C++", seleccione Proyecto vacío, especifique un nombre (en este artículo, se usa "superfastcode") y seleccione Aceptar.Search on "C++", select Empty project, specify a name (this article uses "superfastcode"), and select OK.

    Sugerencia

    Con las herramientas de desarrollo nativo de Python instaladas en Visual Studio 2017, puede comenzar con la plantilla Módulo de extensión de Python, que incluye gran parte de lo que se describe a continuación.With the Python native development tools installed in Visual Studio 2017, you can start with the Python Extension Module template instead, which has much of what's described below already in place. En este tutorial partiremos de un proyecto vacío para mostrar la compilación del módulo de extensión paso a paso.For this walkthrough, though, starting with an empty project demonstrates building the extension module step by step. Una vez que comprenda el proceso, la plantilla le permite ahorrar tiempo al escribir sus propias extensiones.Once you understand the process, the template saves you time when writing your own extensions.

  3. Cree un archivo de C++ en el nuevo proyecto. Para ello, haga clic con el botón derecho en el nodo Archivos de código fuente, seleccione Agregar > Nuevo elemento…, elija Archivo de C++, asígnele el nombre module.cpp y seleccione Aceptar.Create a C++ file in the new project by right-clicking the Source Files node, then select Add > New Item...", select C++ File, name it module.cpp, and select OK.

    Importante

    Para activar las páginas de propiedades de C++ en los pasos siguientes, es necesario un archivo con la extensión .cpp.A file with the .cpp extension is necessary to turn on the C++ property pages in the steps that follow.

  4. Haga clic con el botón derecho en el proyecto de C++ en Solución y seleccione Propiedades.Right-click the C++ project in Solution, select Properties.

  5. En la parte superior del cuadro de diálogo Páginas de propiedades que aparece, establezca Configuración como Todas las configuraciones y Plataforma como Win32.At the top of the Property Pages dialog that appears, set Configuration to All Configurations and Platform to Win32.

  6. Establezca las propiedades específicas tal y como se describe en la tabla siguiente y, luego, seleccione Aceptar.Set the specific properties as described in the following table, then select OK.

    TabTab PropertyProperty ValorValue
    GeneralGeneral General > Nombre de destinoGeneral > Target Name Especifique el nombre del módulo tal y como quiera referirse a él desde Python en las instrucciones from...import.Specify the name of the module as you want to refer to it from Python in from...import statements. Use este mismo nombre en C++ al definir el módulo para Python.You use this same name in the C++ when defining the module for Python. Si quiere utilizar el nombre del proyecto como nombre del módulo, deje el valor predeterminado $(ProjectName).If you want to use the name of the project as the module name, leave the default value of $(ProjectName).
    General > Extensión de destinoGeneral > Target Extension .pyd.pyd
    Valores predeterminados del proyecto > Tipo de configuraciónProject Defaults > Configuration Type Biblioteca dinámica (.dll)Dynamic Library (.dll)
    C/C++ > GeneralC/C++ > General Directorios de inclusión adicionalesAdditional Include Directories Agregue la carpeta include de Python según sea necesario para la instalación; por ejemplo, c:\Python36\include.Add the Python include folder as appropriate for your installation, for example, c:\Python36\include.
    C/C++ > PreprocesadorC/C++ > Preprocessor Definiciones de preprocesadorPreprocessor Definitions Agregue Py_LIMITED_API; al principio de la cadena (incluido el punto y coma).Add Py_LIMITED_API; to the beginning of the string (including the semicolon). Esta definición restringe algunas de las funciones a las que se puede llamar desde Python y hace que el código pueda moverse con mayor facilidad entre versiones diferentes de Python.This definition restricts some of the functions you can call from Python and makes the code more portable between different versions of Python.
    C/C++ > Generación de códigoC/C++ > Code Generation Biblioteca en tiempo de ejecuciónRuntime Library DLL multiproceso (/MD) (vea la advertencia siguiente)Multi-threaded DLL (/MD) (see Warning below)
    Enlazador > GeneralLinker > General Directorios de bibliotecas adicionalesAdditional Library Directories Agregue la carpeta libs de Python que contiene archivos .lib según sea necesario para la instalación, por ejemplo, c:\Python36\libs.Add the Python libs folder containing .lib files as appropriate for your installation, for example, c:\Python36\libs. (Asegúrese de apuntar a la carpeta libs que contiene archivos .lib, y no a la carpeta Lib que contiene archivos .py).(Be sure to point to the libs folder that contains .lib files, and not the Lib folder that contains .py files.)

    Sugerencia

    Si no ve la pestaña C/C++ en las propiedades del proyecto, esto se debe a que este no contiene archivos identificados como archivos de código fuente de C/C++.If you don't see the C/C++ tab in the project properties, it's because the project doesn't contain any files that it identifies as C/C++ source files. Esta condición puede producirse si crea un archivo de código fuente sin una extensión .c o .cpp.This condition can occur if you create a source file without a .c or .cpp extension. Por ejemplo, si ha escrito accidentalmente module.coo en lugar de module.cpp en el anterior cuadro de diálogo Nuevo elemento, Visual Studio creará el archivo pero no establecerá el tipo de archivo en "Código C/C++", que es lo que activa la pestaña de propiedades de C/C++. Este error de identificación se mantiene incluso si cambia el nombre del archivo con la extensión .cpp.For example, if you accidentally entered module.coo instead of module.cpp in the new item dialog earlier, then Visual Studio creates the file but doesn't set the file type to "C/C+ Code," which is what activates the C/C++ properties tab. Such misidentification remains the case even if you rename the file with .cpp. Para establecer el tipo de archivo correctamente, haga clic con el botón derecho en el archivo en el Explorador de soluciones, seleccione Propiedades y establezca Tipo de archivo en Código C/C++.To set the file type properly, right-click the file in Solution Explorer, select Properties, then set File Type to C/C++ Code.

    Advertencia

    Establezca siempre la opción C/C ++ > Generación de código > Biblioteca en tiempo de ejecución como "DLL multiproceso (/MD)", incluso para una configuración de depuración, ya que esta es la configuración con la que se compilan los archivos binarios de Python.Always set the C/C++ > Code Generation > Runtime Library option to "Multi-threaded DLL (/MD)", even for a debug configuration, because this setting is what the non-debug Python binaries are built with. Si, por accidente, establece la opción "DLL de depuración multiproceso (/MDd)", al compilar una configuración de depuración, se producirá el error C1189: Py_LIMITED_API no es compatible con Py_DEBUG, Py_TRACE_REFS ni Py_REF_DEBUG.If you happen to set the "Multi-threaded Debug DLL (/MDd)" option, building a Debug configuration produces error C1189: Py_LIMITED_API is incompatible with Py_DEBUG, Py_TRACE_REFS, and Py_REF_DEBUG. Además, si quita Py_LIMITED_API para evitar el error de compilación, Python se bloqueará al intentar importar el módulo.Furthermore, if you remove Py_LIMITED_API to avoid the build error, Python crashes when attempting to import the module. (El bloqueo se produce en la llamada del archivo DLL a PyModule_Create, como se describe más adelante, con el mensaje de salida Fatal Python error: PyThreadState_Get: no current thread [Error irrecuperable Python: PyThreadState_Get: ningún subproceso actual]).(The crash happens within the DLL's call to PyModule_Create as described later, with the output message of Fatal Python error: PyThreadState_Get: no current thread.)

    La opción /MDd se usa para compilar los binarios de depuración de Python (como python_d.exe), pero, si se selecciona para un archivo DLL de extensión, también se producirá el error de compilación con Py_LIMITED_API.The /MDd option is used to build the Python debug binaries (such as python_d.exe), but selecting it for an extension DLL still causes the build error with Py_LIMITED_API.

  7. Haga clic con el botón derecho en el proyecto de C++ y seleccione Compilar para probar sus configuraciones (de depuración y de lanzamiento).Right-click the C++ project and select Build to test your configurations (both Debug and Release). Los archivos .pyd están en la carpeta solución en Depuración y Lanzamiento, no en la carpeta del proyecto de C++.The .pyd files are located in the solution folder under Debug and Release, not the C++ project folder itself.

  8. Agregue el código siguiente al archivo module.cpp del proyecto de C++:Add the following code to the C++ project's module.cpp file:

    #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);
    }
    
  9. Compile el proyecto de C++ para confirmar que el código es correcto.Build the C++ project again to confirm that your code is correct.

Convertir el proyecto de C++ a una extensión para PythonConvert the C++ project to an extension for Python

Para convertir el DLL de C++ en una extensión para Python, debe modificar primero los métodos exportados de modo que interactúen con tipos de Python.To make the C++ DLL into an extension for Python, you first modify the exported methods to interact with Python types. Después, debe agregar una función que exporte el módulo, junto con las definiciones de los métodos del módulo.You then add a function that exports the module, along with definitions of the module's methods.

Para obtener información sobre lo que se muestra en esta sección acerca de Python 3.x, consulte el Manual de referencia de la API de Python/C y especialmente Objetos de módulo en python.org (recuerde que debe seleccionar la versión de Python en el control desplegable de la esquina superior derecha para ver la documentación correcta).For background on what's shown in this section for Python 3.x, refer to the Python/C API Reference Manual and especially Module Objects on python.org (remember to select your version of Python from the drop-down control on the upper right to view the correct documentation).

Si está trabajando con Python 2.7, consulte en su lugar Extending Python 2.7 with C or C++ (Extensión de Python 2.7 con C o C++) y Porting Extension Modules to Python 3 (Migración de módulos de extensión a Python 3) (python.org).If you're working with Python 2.7, refer instead to Extending Python 2.7 with C or C++ and Porting Extension Modules to Python 3 (python.org).

  1. En el archivo de C++, incluya Python.h en la parte superior:In the C++ file, include Python.h at the top:

    #include <Python.h>
    
  2. Modifique el método tanh_impl para aceptar y devolver tipos de Python (PyOjbect*).Modify the tanh_impl method to accept and return Python types (a PyOjbect*, that is):

    PyObject* tanh_impl(PyObject *, PyObject* o) {
        double x = PyFloat_AsDouble(o);
        double tanh_x = sinh_impl(x) / cosh_impl(x);
        return PyFloat_FromDouble(tanh_x);
    }
    
  3. Agregue una estructura que defina la manera en que la función tanh_impl de C++ se muestra en Python:Add a structure that defines how the C++ tanh_impl function is presented to Python:

    static PyMethodDef superfastcode_methods[] = {
        // The first property is the name exposed to Python, fast_tanh, the second is the C++
        // function name that contains the implementation.
        { "fast_tanh", (PyCFunction)tanh_impl, METH_O, nullptr },
    
        // Terminate the array with an object containing nulls.
        { nullptr, nullptr, 0, nullptr }
    };
    
  4. Agregue una estructura que defina el módulo como quiere que se haga referencia a él en el código de Python, concretamente cuando se usa la instrucción from...import.Add a structure that defines the module as you want to refer to it in your Python code, specifically when using the from...import statement. (hágalo coincidir con el valor de las propiedades del proyecto en Propiedades de configuración > General > Nombre de destino). En el ejemplo siguiente, el nombre de módulo "superfastcode" significa que puede usar from superfastcode import fast_tanh en Python, porque fast_tanh se define en superfastcode_methods.(Make this match the value in the project properties under Configuration Properties > General > Target Name.) In the following example, the "superfastcode" module name means you can use from superfastcode import fast_tanh in Python, because fast_tanh is defined within superfastcode_methods. (Los nombres de archivo internos del proyecto de C++, como module.cpp, no tienen importancia).(Filenames internal to the C++ project, like module.cpp, are inconsequential.)

    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
    };
    
  5. Agregue un método al que Python llame cuando cargue el módulo, con el nombre PyInit_<module-name>, donde <module_name> debe coincidir exactamente con la propiedad General > Nombre de destino del proyecto de C++ (es decir, coincide con el nombre del archivo .pyd compilado por el proyecto).Add a method that Python calls when it loads the module, which must be named PyInit_<module-name>, where <module_name> exactly matches the C++ Project's General > Target Name property (that is, it matches the filename of the .pyd built by the project).

    PyMODINIT_FUNC PyInit_superfastcode() {
        return PyModule_Create(&superfastcode_module);
    }
    
  6. Establezca la configuración de destino en "Versión" y compile el proyecto de C++ de nuevo para comprobar el código.Set the target configuration to "Release" and build the C++ project again to verify your code. Si se producen errores, realice las siguientes comprobaciones:If you encounter errors, check the following cases:

    • No se puede localizar Python.h (E1696: no se puede abrir el archivo de origen "Python.h" o C1083: no se puede abrir el archivo de inclusión "Python.h": no existe tal archivo o directorio): verifique que la ruta de acceso en C/C ++ > General > Directorios de inclusión adicionales de las propiedades del proyecto señala la carpeta include de la instalación de Python.Unable to locate Python.h (E1696: cannot open source file "Python.h" and/or C1083: Cannot open include file: "Python.h": No such file or directory): verify that the path in C/C++ > General > Additional Include Directories in the project properties points to your Python installation's include folder. Consulte el paso 6 en Crear el proyecto de C++ principal.See step 6 under Create the core C++ project.
    • No se pueden encontrar las bibliotecas de Python: compruebe que la ruta de acceso de Enlazador > General > Directorios de bibliotecas adicionales de las propiedades del proyecto apunta a la carpeta libs de instalación de Python.Unable to locate Python libraries: verify that the path in Linker > General > Additional Library Directories in the project properties points to your Python installation's libs folder. Consulte el paso 6 en Crear el proyecto de C++ principal.See step 6 under Create the core C++ project.
    • Errores del enlazador relacionados con la arquitectura de destino: cambie la arquitectura del proyecto del destino de C++ para que coincida con la de la instalación de Python.Linker errors related to target architecture: change the C++ target's project architecture to match that of your Python installation. Por ejemplo, si tiene como destino x64 con el proyecto de C++, pero la instalación de Python es x86, cambie el proyecto de C++ para que tenga como destino x86.For example, if you're targeting x64 with the C++ project but your Python installation is x86, change the C++ project to target x86.

Probar el código y comparar los resultadosTest the code and compare the results

Ahora que tiene el archivo DLL estructurado como una extensión de Python, puede hacer referencia a él desde el proyecto de Python, importar el módulo y usar sus métodos.Now that you have the DLL structured as a Python extension, you can refer to it from the Python project, import the module, and use its methods.

Poner el archivo DLL a disposición de PythonMake the DLL available to Python

Hay dos maneras de hacer que el archivo DLL esté disponible para Python.There are two ways to make the DLL available to Python.

El primer método funciona si el proyecto de Python y el de C++ se encuentran en la misma solución.The first method works if the Python project and the C++ project are in the same solution. Vaya al Explorador de soluciones, haga clic con el botón derecho en el nodo Referencias del proyecto de Python y, después, seleccione Agregar referencia.Go to Solution Explorer, right-click the References node in your Python project, and then select Add Reference. En el cuadro de diálogo que aparecerá, seleccione la ficha Proyectos, el proyecto superfastcode (o el nombre que esté usando) y Aceptar.In the dialog that appears, select the Projects tab, select the superfastcode project (or whatever name you're using), and then OK.

Agregar una referencia al proyecto superfastcode

El método alternativo, que se describe en los pasos siguientes, instala el módulo en el entorno global de Python, lo que hace que esté disponible también para otros proyectos de Python.The alternate method, described in the following steps, installs the module in the global Python environment, making it available to other Python projects as well. Normalmente, realizar esta acción requiere actualizar la base de datos de finalización de IntelliSense para ese entorno en Visual Studio 2017, versión 15.5 y anteriores.(Doing so typically requires that you refresh the IntelliSense completion database for that environment in Visual Studio 2017 version 15.5 and earlier. También es necesario actualizar al quitar el módulo del entorno.Refreshing is also necessary when removing the module from the environment.)

  1. Si usa Visual Studio 2017, ejecute el instalador de Visual Studio, seleccione Modificar, seleccione Componentes individuales > Compiladores, herramientas de compilación y entornos de ejecución > Conjunto de herramientas de Visual C++ 2015.3 v140.If you're using Visual Studio 2017, run the Visual Studio installer, select Modify, select Individual Components > Compilers, build tools, and runtimes > Visual C++ 2015.3 v140 toolset. Este paso es necesario porque que Python (para Windows) se compila con Visual Studio 2015 (versión 14.0) y espera que esas herramientas estén disponibles al compilar una extensión mediante el método descrito aquí.This step is necessary because Python (for Windows) is itself built with Visual Studio 2015 (version 14.0) and expects that those tools are available when building an extension through the method described here. (tenga en cuenta que puede que necesite instalar una versión de 32 bits de Python y establecer el DLL como Win32 y no como x64).(Note that you may need to install a 32-bit version of Python and target the DLL to Win32 and not x64.)

  2. Cree un archivo denominado setup.py en el proyecto de C++ haciendo clic con el botón derecho en el proyecto y seleccionando Agregar > Nuevo elemento. Luego, seleccione "Archivo C++ (.cpp)", asigne el nombre setup.py al archivo y seleccione Aceptar (al nombrar el archivo con la extensión .py, Visual Studio lo reconoce como Python aunque use la plantilla de archivos de C++).Create a file named setup.py in your C++ project by right-clicking the project and selecting Add > New Item.... Then select "C++ File (.cpp)", name the file setup.py, and selecting OK (naming the file with the .py extension makes Visual Studio recognize it as Python despite using the C++ file template). Cuando el archivo aparezca en el editor, pegue el código siguiente en él:When the file appears in the editor, paste the following code into it:

    from distutils.core import setup, Extension, DEBUG
    
    sfc_module = Extension('superfastcode', sources = ['module.cpp'])
    
    setup(name = 'superfastcode', version = '1.0',
        description = 'Python Package with superfastcode C++ extension',
        ext_modules = [sfc_module]
        )
    

    Vea Building C and C++ Extensions (Compilación de extensiones de C y C++) en python.org para obtener la documentación de este script.See Building C and C++ extensions (python.org) for documentation on this script.

  3. El código setup.py le indica a Python que debe compilar la extensión que usa el conjunto de herramientas de C++ de Visual Studio 2015 cuando se use desde la línea de comandos.The setup.py code instructs Python to build the extension using the Visual Studio 2015 C++ toolset when used from the command line. Abra un símbolo del sistema con privilegios elevados, vaya a la carpeta que contiene el proyecto de C++ (es decir, la carpeta que contenga setup.py) y escriba el comando siguiente:Open an elevated command prompt, navigate to the folder containing the C++ project (that is, the folder that contains setup.py), and enter the following command:

    pip install .
    

Llamar al archivo DLL desde PythonCall the DLL from Python

Después de haber completado cualquiera de los métodos anteriores, puede llamar a la función fast_tanh desde el código de Python y comparar su rendimiento con la implementación de Python:After you've completed either of the methods above, you can now call the fast_tanh function from Python code and compare its performance to the Python implementation:

  1. Agregue las líneas siguientes en el archivo .py para llamar al método fast_tanh exportado desde el archivo DLL y mostrar el resultado.Add the following lines in your .py file to call the fast_tanh method exported from the DLL and display its output.

    from superfastcode import fast_tanh
    test(lambda d: [fast_tanh(x) for x in d], '[fast_tanh(x) for x in d]')
    
  2. Ejecute el programa de Python (Depurar > Iniciar sin depurar o Ctrl + F5) y observe que la rutina de C++ se ejecuta de cinco a veinte veces más rápido que la implementación de Python.Run the Python program (Debug > Start Without Debugging or Ctrl+F5) and observe that the C++ routine runs five to 20 times faster than the Python implementation. El resultado típico se muestra de la manera siguiente:Typical output appears as follows:

    Running benchmarks with COUNT = 500000
    sequence_tanh took 1.542 seconds
    
    [tanh(x) for x in d] took 1.087 seconds
    
    [fast_tanh(x) for x in d] took 0.158 seconds
    
  3. Intente aumentar la variable COUNT para que las diferencias sean más pronunciadas.Try increasing the COUNT variable so that the differences are more pronounced. Una compilación de depuración del módulo de C++ también se ejecuta de forma más lenta que una compilación de depuración, ya que esta última está menos optimizada y contiene varias comprobaciones de errores.A Debug build of the C++ module also runs slower than a Release build because the Debug build is less optimized and contains various error checks. No dude en alternar entre dichas configuraciones para compararlas.Feel free to switch between those configurations for comparison.

Depurar el código de C++Debug the C++ code

Visual Studio admite la depuración de código Python y C++ de forma conjunta.Visual Studio supports debugging Python and C++ code together.

  1. Haga clic con el botón derecho en el proyecto de Python en el Explorador de soluciones, seleccione Propiedades, elija la pestaña Depurar y, después, seleccione la opción Depurar > Habilitar depuración de código nativo.Right-click the Python project in Solution Explorer, select Properties, select the Debug tab, and then select the Debug > Enable native code debugging option.

    Sugerencia

    Cuando se habilita la depuración de código nativo, la ventana de salida de Python podría desaparecer de inmediato al completarse el programa, sin ofrecer la pausa habitual "Presione cualquier tecla para continuar…".When you enable native code debugging, the Python output window may disappear immediately when the program has completed without giving you the usual "Press any key to continue..." pause. Para forzar una pausa, agregue la opción -i al campo Ejecutar > Argumentos del intérprete en la pestaña Depurar al habilitar la depuración de código nativo.To force a pause, add the -i option to the Run > Interpreter Arguments field on the Debug tab when you enable native code debugging. Este argumento colocará el intérprete de Python en modo interactivo cuando finalice el código, momento en que esperará a que presione Ctrl+Z, ENTRAR para salir.This argument puts the Python interpreter into interactive mode after the code finishes, at which point it waits for you to press Ctrl+Z, Enter to exit. (Como alternativa, si no le importa modificar el código de Python, puede agregar las instrucciones import os y os.system("pause") al final del programa.(Alternately, if you don't mind modifying your Python code, you can add import os and os.system("pause") statements at the end of your program. Este código duplica la petición de pausa original).This code duplicates the original pause prompt.)

  2. Seleccione Archivo > Guardar para guardar los cambios de propiedad.Select File > Save to save the property changes.

  3. Establezca la configuración de compilación como "Depurar" en la barra de herramientas de Visual Studio.Set the build configuration to "Debug" in the Visual Studio toolbar.

    Establecer la configuración de compilación como Depurar

  4. Puesto que el código normalmente tarda más tiempo en ejecutarse en el depurador, puede que le interese cambiar la variable COUNT del archivo .py a un valor que sea unas cinco veces más pequeño (por ejemplo, cambiarlo de 500000 a 100000).Because code generally takes longer to run in the debugger, you may want to change the COUNT variable in your .py file to a value that's about five times smaller (for example, change it from 500000 to 100000).

  5. En el código de C++, establezca un punto de interrupción en la primera línea del método tanh_impl e inicie el depurador (F5 o Depurar > Iniciar depuración).In your C++ code, set a breakpoint on the first line of the tanh_impl method, then start the debugger (F5 or Debug > Start Debugging). El depurador se detendrá cuando se realice la llamada a ese código.The debugger stops when that code is called. Si no se alcanza el punto de interrupción, compruebe que la configuración esté establecida como Depurar y que haya guardado el proyecto (esto no se realiza automáticamente al iniciar al depurador).If the breakpoint is not hit, check that the configuration is set to Debug and that you've saved the project (which does not happen automatically when starting the debugger).

    Detener en un punto de interrupción en el código de C++

  6. En este punto puede recorrer el código de C++, examinar las variables, etc.At this point you can step through the C++ code, examine variables, and so on. Estas características se detallan en Depuración conjunta de Python y C++.These features are detailed in Debugging C++ and Python Together.

Enfoques alternativosAlternative approaches

Existen diversos métodos para crear extensiones de Python, como se describe en la tabla siguiente.There are a variety of means to create Python extensions as described in the following table. La primera entrada de CPython es lo que se ha tratado ya en este tema.The first entry for CPython is what's been discussed in this article already.

EnfoqueApproach AñoVintage Usuarios representativosRepresentative User(s) VentajasPro(s) InconvenientesCon(s)
Módulos de extensión de C/C++ para CPythonC/C++ extension modules for CPython 19911991 biblioteca estándarStandard Library Amplia documentación y tutoriales.Extensive documentation and tutorials. Control total.Total control. Compilación, portabilidad, administración de referencias.Compilation, portability, reference management. Extensos conocimientos de C.High C knowledge.
pybind11 (recomendado para C++)pybind11 (Recommended for C++) 20152015 Biblioteca ligera de solo encabezados para crear los enlaces de Python de código de C++ existente.Lightweight, header-only library for creating Python bindings of existing C++ code. Pocas dependencias.Few dependencies. Compatibilidad con PyPy.PyPy compatibility. Más reciente, menos maduro.Newer, less mature. Uso intensivo de características de C++11.Heavy use of C++11 features. Lista reducida de compiladores compatibles (incluye Visual Studio).Short list of supported compilers (Visual Studio is included).
Cython (recomendado para C)Cython (Recommnded for C) 20072007 gevent, kivygevent, kivy Semejante a Python.Python-like. Muy maduro.Highly mature. Alto rendimiento.High performance. Compilación, nueva sintaxis y nueva cadena de herramientas.Compilation, new syntax, new toolchain.
Boost.PythonBoost.Python 20022002 Funciona con casi todos los compiladores de C++.Works with just about every C++ compiler. Conjunto grande y complejo de bibliotecas; contiene muchas soluciones alternativas para los compiladores anteriores.Large and complex suite of libraries; contains many workarounds for old compilers.
ctypesctypes 20032003 oscryptooscrypto Sin compilación, amplia disponibilidad.No compilation, wide availability. El acceso y la mutación de estructuras de C son complicados y propensos a errores.Accessing and mutating C structures cumbersome and error prone.
SWIGSWIG 19961996 crfsuitecrfsuite Generar enlaces para muchos lenguajes a la vez.Generate bindings for many languages at once. Sobrecarga excesiva si Python es el único destino.Excessive overhead if Python is the only target.
cfficffi 20132013 cryptography, pypycryptography, pypy Facilidad de integración, compatibilidad con PyPy.Ease of integration, PyPy compatibility. Más reciente, menos maduro.Newer, less mature.

Vea tambiénSee also

El ejemplo completo de este tutorial se puede encontrar en python-samples-vs-cpp-extension (GitHub).The completed sample from this walkthrough can be found on python-samples-vs-cpp-extension (GitHub).