# Introducción

La interfaz del programador de aplicaciones (API) con Python brinda a los programadores de C y C++ acceso al intérprete de Python en una variedad de niveles. La API es igualmente utilizable desde C++, pero por brevedad generalmente se conoce como la API Python/C. Hay dos razones fundamentalmente diferentes para usar la API Python/C. La primera razón es escribir módulos de extensión para propósitos específicos; Estos son módulos C que extienden el intérprete de Python. Este es probablemente el uso más común. La segunda razón es usar Python como componente en una aplicación más grande; Esta técnica se conoce generalmente como integración (embedding) Python en una aplicación.

Escribir un módulo de extensión es un proceso relativamente bien entendido, donde un enfoque de «libro de cocina» (cookbook) funciona bien. Hay varias herramientas que automatizan el proceso hasta cierto punto. Si bien las personas han integrado Python en otras aplicaciones desde su existencia temprana, el proceso de integrar Python es menos sencillo que escribir una extensión.

Muchas funciones API son útiles independientemente de si está integrando o extendiendo Python; Además, la mayoría de las aplicaciones que integran Python también necesitarán proporcionar una extensión personalizada, por lo que probablemente sea una buena idea familiarizarse con la escritura de una extensión antes de intentar integrar Python en una aplicación real.

## Estándares de codificación

Si está escribiendo código C para su inclusión en CPython, debe seguir las pautas y estándares definidos en PEP 7. Estas pautas se aplican independientemente de la versión de Python a la que esté contribuyendo. Seguir estas convenciones no es necesario para sus propios módulos de extensión de terceros, a menos que eventualmente espere contribuir con ellos a Python.

## Archivos de cabecera (Include)

Todas las definiciones de función, tipo y macro necesarias para usar la API Python/C se incluyen en su código mediante la siguiente línea:

    #define PY_SSIZE_T_CLEAN
    #include <Python.h>

Esto implica la inclusión de los siguientes archivos de encabezado estándar: `<stdio.h>`, `<string.h>`, `<errno.h>`, `<limits.h>`, `<assert.h>` y `<stdlib.h>` (si está disponible).

Nota

Dado que Python puede definir algunas definiciones de preprocesador que afectan los encabezados estándar en algunos sistemas, debe incluir `Python.h` antes de incluir encabezados estándar.

Se recomienda definir siempre `PY_SSIZE_T_CLEAN` antes de incluir `Python.h`. Consulte Analizando argumentos y construyendo valores para obtener una descripción de este macro.

Todos los nombres visibles del usuario definidos por `Python.h` (excepto los definidos por los encabezados estándar incluidos) tienen uno de los prefijos `Py` o `_Py`. Los nombres que comienzan con `_Py` son para uso interno de la implementación de Python y no deben ser utilizados por escritores de extensiones. Los nombres de miembros de estructura no tienen un prefijo reservado.

Nota

El código de usuario nunca debe definir nombres que comiencen con `Py` o `_Py`. Esto confunde al lector y pone en peligro la portabilidad del código de usuario para futuras versiones de Python, que pueden definir nombres adicionales que comienzan con uno de estos prefijos.

Los archivos de encabezado generalmente se instalan con Python. En Unix, estos se encuentran en los directorios `prefix/include/pythonversion/` y `exec_prefix/include/pythonversion/`, donde `prefix` y `exec_prefix` están definidos por los parámetros correspondientes al programa de Python configure y version es `'%d.%d' % sys.version_info[:2]`. En Windows, los encabezados se instalan en `prefix/include`, donde `prefix` es el directorio de instalación especificado para el instalador.

Para incluir los encabezados, coloque ambos directorios (si son diferentes) en la ruta de búsqueda de su compilador para incluir. No coloque los directorios principales en la ruta de búsqueda y luego use `#include <pythonX.Y/Python.h>`; esto se romperá en las compilaciones multiplataforma ya que los encabezados independientes de la plataforma bajo `prefix` incluyen los encabezados específicos de la plataforma de `exec_prefix`.

Los usuarios de C++ deben tener en cuenta que aunque la API se define completamente usando C, los archivos de encabezado declaran correctamente que los puntos de entrada son `extern "C"`. Como resultado, no es necesario hacer nada especial para usar la API desde C++.

## Macros útiles

Varias macros útiles se definen en los archivos de encabezado de Python. Muchos se definen más cerca de donde son útiles (por ejemplo `Py_RETURN_NONE`). Otros de una utilidad más general se definen aquí. Esto no es necesariamente una lista completa.

`Py_UNREACHABLE`()

  Use esto cuando tenga una ruta de código que no espera alcanzar. Por ejemplo, en la cláusula `default:` en una declaración `switch` para la cual todos los valores posibles están cubiertos en las declaraciones `case`. Use esto en lugares donde podría sentirse tentado a poner una llamada `assert(0)` o `abort()`.

  Nuevo en la versión 3.7.

`Py_ABS`(x)

  Retorna el valor absoluto de `x`.

  Nuevo en la versión 3.3.

`Py_MIN`(x, y)

  Retorna el valor mínimo entre `x` e `y`.

  Nuevo en la versión 3.3.

`Py_MAX`(x, y)

  Retorna el valor máximo entre `x` e `y`.

  Nuevo en la versión 3.3.

`Py_STRINGIFY`(x)

  Convierte `x` en una cadena de caracteres C. Por ejemplo, `Py_STRINGIFY(123)` retorna `"123"`.

  Nuevo en la versión 3.4.

`Py_MEMBER_SIZE`(type, member)

  Retorna el tamaño de una estructura (`type`) `member` en bytes.

  Nuevo en la versión 3.6.

`Py_CHARMASK`(c)

  El argumento debe ser un carácter o un número entero en el rango [-128, 127] o [0, 255]. Este macro retorna la conversión `c` a un `unsigned char`.

`Py_GETENV`(s)

  Al igual que `getenv(s)`, pero retorna `NULL` si: la opción `-E` se pasó en la línea de comando (es decir, si se establece `Py_IgnoreEnvironmentFlag`).

`Py_UNUSED`(arg)

  Use esto para argumentos no utilizados en una definición de función para silenciar las advertencias del compilador. Ejemplo: `int func(int a, int Py_UNUSED(b)) {return a; }`.

  Nuevo en la versión 3.4.

`Py_DEPRECATED`(version)

  Use esto para declaraciones obsoletas. El macro debe colocarse antes del nombre del símbolo.

  Ejemplo:

      Py_DEPRECATED(3.8) PyAPI_FUNC(int) Py_OldFunction(void);

  Distinto en la versión 3.8: Soporte para MSVC fue agregado.

`PyDoc_STRVAR`(name, str)

  Crea una variable con el nombre `name` que se puede usar en docstrings. Si Python se construye sin docstrings, el valor estará vacío.

  Utilice `PyDoc_STRVAR` para que los docstrings admitan la construcción de Python sin docstrings, como se especifica en PEP 7.

  Ejemplo:

      PyDoc_STRVAR(pop_doc, "Remove and return the rightmost element.");

      static PyMethodDef deque_methods[] = {
          // ...
          {"pop", (PyCFunction)deque_pop, METH_NOARGS, pop_doc},
          // ...
      }

`PyDoc_STR`(str)

  Crea un docstring para la cadena de caracteres de entrada dada o una cadena vacía si los docstrings están deshabilitados.

  Utilice `PyDoc_STR` al especificar docstrings para admitir la construcción de Python sin docstrings, como se especifica en PEP 7.

  Ejemplo:

      static PyMethodDef pysqlite_row_methods[] = {
          {"keys", (PyCFunction)pysqlite_row_keys, METH_NOARGS,
              PyDoc_STR("Returns the keys of the row.")},
          {NULL, NULL}
      };

## Objetos, Tipos y Conteos de Referencias

Most Python/C API functions have one or more arguments as well as a return value of type `PyObject*`. This type is a pointer to an opaque data type representing an arbitrary Python object. Since all Python object types are treated the same way by the Python language in most situations (e.g., assignments, scope rules, and argument passing), it is only fitting that they should be represented by a single C type. Almost all Python objects live on the heap: you never declare an automatic or static variable of type `PyObject`, only pointer variables of type `PyObject*` can be declared. The sole exception are the type objects; since these must never be deallocated, they are typically static `PyTypeObject` objects.

Todos los objetos de Python (incluso los enteros de Python) tienen un tipo (type) y un conteo de referencia (reference count). El tipo de un objeto determina qué tipo de objeto es (por ejemplo, un número entero, una lista o una función definida por el usuario; hay muchos más como se explica en Jerarquía de tipos estándar). Para cada uno de los tipos conocidos hay un macro para verificar si un objeto es de ese tipo; por ejemplo, `PyList_Check(a)` es verdadero si (y solo si) el objeto al que apunta a es una lista de Python.

### Conteo de Referencias

El conteo de referencia es importante porque las computadoras de hoy tienen un tamaño de memoria finito (y a menudo muy limitado); cuenta cuántos lugares diferentes hay los cuales tienen una referencia a un objeto. Tal lugar podría ser otro objeto, o una variable C global (o estática), o una variable local en alguna función C. Cuando el recuento de referencia de un objeto se convierte en cero, el objeto se desasigna. Si contiene referencias a otros objetos, su recuento de referencias se reduce. Esos otros objetos pueden ser desasignados a su vez, si esta disminución hace que su recuento de referencia sea cero, y así sucesivamente. (Hay un problema obvio con los objetos que se refieren entre sí aquí; por ahora, la solución es «no hagas eso»).

Los conteos de referencias siempre se manipulan explícitamente. La forma normal es usar el macro `Py_INCREF()` para incrementar el conteo de referencia de un objeto en uno, y `Py_DECREF()` para disminuirlo en uno. El macro `Py_DECREF()` es considerablemente más compleja que la incref, ya que debe verificar si el recuento de referencia se convierte en cero y luego hacer que se llame al desasignador (deallocator) del objeto. El desasignador es un puntero de función contenido en la estructura de tipo del objeto. El desasignador específico del tipo se encarga de disminuir los recuentos de referencia para otros objetos contenidos en el objeto si este es un tipo de objeto compuesto, como una lista, así como realizar cualquier finalización adicional que sea necesaria. No hay posibilidad de que el conteo de referencia se desborde; se utilizan al menos tantos bits para contener el recuento de referencia como ubicaciones de memoria distintas en la memoria virtual (suponiendo `sizeof(Py_ssize_t) >= sizeof(void*)`). Por lo tanto, el incremento del recuento de referencia es una operación simple.

No es necesario incrementar el conteo de referencia de un objeto para cada variable local que contiene un puntero a un objeto. En teoría, el conteo de referencia del objeto aumenta en uno cuando se hace que la variable apunte hacia él y disminuye en uno cuando la variable se sale del alcance. Sin embargo, estos dos se cancelan entre sí, por lo que al final el recuento de referencias no ha cambiado. La única razón real para usar el recuento de referencia es evitar que el objeto pierda su asignación mientras nuestra variable lo apunte. Si sabemos que hay al menos otra referencia al objeto que vive al menos tanto como nuestra variable, no hay necesidad de incrementar el recuento de referencias temporalmente. Una situación importante donde esto surge es en los objetos que se pasan como argumentos a las funciones de C en un módulo de extensión que se llama desde Python; El mecanismo de llamada garantiza mantener una referencia a cada argumento durante la duración de la llamada.

Sin embargo, una trampa común es extraer un objeto de una lista y mantenerlo por un tiempo sin incrementar su conteo de referencia. Es posible que alguna otra operación elimine el objeto de la lista, disminuya su conteo de referencias y posiblemente lo desasigne. El peligro real es que las operaciones de aspecto inocente pueden invocar código arbitrario de Python que podría hacer esto; hay una ruta de código que permite que el control vuelva al usuario desde a `Py_DECREF()`, por lo que casi cualquier operación es potencialmente peligrosa.

Un enfoque seguro es utilizar siempre las operaciones genéricas (funciones cuyo nombre comienza con `PyObject_`, `PyNumber_`, `PySequence_` o `PyMapping_`). Estas operaciones siempre incrementan el recuento de referencia del objeto que retornan. Esto deja a la persona que llama con la responsabilidad de llamar `Py_DECREF()` cuando hayan terminado con el resultado; Esto pronto se convierte en una segunda naturaleza.

#### Detalles del conteo de referencia

El comportamiento del conteo de referencias de funciones en la API de Python/C se explica mejor en términos de propiedad de las referencias. La propiedad pertenece a referencias, nunca a objetos (los objetos no son propiedad: siempre se comparten). «Poseer una referencia» significa ser responsable de llamar a `Py_DECREF` cuando ya no se necesita la referencia. La propiedad también se puede transferir, lo que significa que el código que recibe la propiedad de la referencia se hace responsable de eventualmente decretarla llamando a `Py_DECREF()` o `Py_XDECREF()` cuando ya no es necesario — o transmitir esta responsabilidad (generalmente a la persona que llama). Cuando una función transfiere la propiedad de una referencia a su llamador, se dice que el que llama recibe una nueva referencia. Cuando no se transfiere ninguna propiedad, se dice que la persona que llama toma prestada la referencia. No es necesario hacer nada para obtener una referencia prestada.

Por el contrario, cuando una función de llamada pasa una referencia a un objeto, hay dos posibilidades: la función roba una referencia al objeto, o no lo hace. Robar una referencia significa que cuando pasa una referencia a una función, esa función asume que ahora posee esa referencia, y usted ya no es responsable de ella.

Pocas funciones roban referencias; las dos excepciones notables son `PyList_SetItem()` y `PyTuple_SetItem()`, que roban una referencia al elemento (¡pero no a la tupla o lista en la que se coloca el elemento!). Estas funciones fueron diseñadas para robar una referencia debido a un idioma común para poblar una tupla o lista con objetos recién creados; por ejemplo, el código para crear la tupla `(1, 2, "tres")` podría verse así (olvidando el manejo de errores por el momento; una mejor manera de codificar esto se muestra a continuación):

    PyObject *t;

    t = PyTuple_New(3);
    PyTuple_SetItem(t, 0, PyLong_FromLong(1L));
    PyTuple_SetItem(t, 1, PyLong_FromLong(2L));
    PyTuple_SetItem(t, 2, PyUnicode_FromString("three"));

Aquí `PyLong_FromLong()` retorna una nueva referencia que es inmediatamente robada por `PyTuple_SetItem()`. Cuando quiera seguir usando un objeto aunque se le robe la referencia, use `Py_INCREF()` para tomar otra referencia antes de llamar a la función de robo de referencias.

Por cierto, `PyTuple_SetItem()` es la única forma de establecer elementos de tupla; `PySequence_SetItem()` y `PyObject_SetItem()` se niegan a hacer esto ya que las tuplas son un tipo de datos inmutable. Solo debe usar `PyTuple_SetItem()` para las tuplas que está creando usted mismo.

El código equivalente para llenar una lista se puede escribir usando `PyList_New()` y `PyList_SetItem()`.

Sin embargo, en la práctica, rara vez utilizará estas formas de crear y completar una tupla o lista. Hay una función genérica, `Py_BuildValue()`, que puede crear los objetos más comunes a partir de valores C, dirigidos por un una cadena de caracteres de formato (format string). Por ejemplo, los dos bloques de código anteriores podrían reemplazarse por lo siguiente (que también se ocupa de la comprobación de errores):

    PyObject *tuple, *list;

    tuple = Py_BuildValue("(iis)", 1, 2, "three");
    list = Py_BuildValue("[iis]", 1, 2, "three");

Es mucho más común usar `PyObject_SetItem()` y amigos con elementos cuyas referencias solo está prestando, como argumentos que se pasaron a la función que está escribiendo. En ese caso, su comportamiento con respecto a los recuentos de referencias es mucho más sensato, ya que no tiene que incrementar un recuento de referencias para poder regalar una referencia («robarla»). Por ejemplo, esta función establece todos los elementos de una lista (en realidad, cualquier secuencia mutable) en un elemento dado:

    int
    set_all(PyObject *target, PyObject *item)
    {
        Py_ssize_t i, n;

        n = PyObject_Length(target);
        if (n < 0)
            return -1;
        for (i = 0; i < n; i++) {
            PyObject *index = PyLong_FromSsize_t(i);
            if (!index)
                return -1;
            if (PyObject_SetItem(target, index, item) < 0) {
                Py_DECREF(index);
                return -1;
            }
            Py_DECREF(index);
        }
        return 0;
    }

La situación es ligeramente diferente para los valores de retorno de la función. Si bien pasar una referencia a la mayoría de las funciones no cambia sus responsabilidades de propiedad para esa referencia, muchas funciones que retornan una referencia a un objeto le otorgan la propiedad de la referencia. La razón es simple: en muchos casos, el objeto retornado se crea sobre la marcha, y la referencia que obtiene es la única referencia al objeto. Por lo tanto, las funciones genéricas que retornan referencias de objeto, como `PyObject_GetItem()` y `PySequence_GetItem()`, siempre retornan una nueva referencia (la entidad que llama se convierte en el propietario de la referencia).

Es importante darse cuenta de que si posee una referencia retornada por una función depende de a qué función llame únicamente — el plumaje (el tipo del objeto pasado como argumento a la función) no entra en él! Por lo tanto, si extrae un elemento de una lista usando `PyList_GetItem()`, no posee la referencia — pero si obtiene el mismo elemento de la misma lista usando `PySequence_GetItem()` (que toma exactamente los mismos argumentos), usted posee una referencia al objeto retornado.

Aquí hay un ejemplo de cómo podría escribir una función que calcule la suma de los elementos en una lista de enteros; una vez usando `PyList_GetItem()`, y una vez usando `PySequence_GetItem()`.

    long
    sum_list(PyObject *list)
    {
        Py_ssize_t i, n;
        long total = 0, value;
        PyObject *item;

        n = PyList_Size(list);
        if (n < 0)
            return -1; /* Not a list */
        for (i = 0; i < n; i++) {
            item = PyList_GetItem(list, i); /* Can't fail */
            if (!PyLong_Check(item)) continue; /* Skip non-integers */
            value = PyLong_AsLong(item);
            if (value == -1 && PyErr_Occurred())
                /* Integer too big to fit in a C long, bail out */
                return -1;
            total += value;
        }
        return total;
    }

    long
    sum_sequence(PyObject *sequence)
    {
        Py_ssize_t i, n;
        long total = 0, value;
        PyObject *item;
        n = PySequence_Length(sequence);
        if (n < 0)
            return -1; /* Has no length */
        for (i = 0; i < n; i++) {
            item = PySequence_GetItem(sequence, i);
            if (item == NULL)
                return -1; /* Not a sequence, or other failure */
            if (PyLong_Check(item)) {
                value = PyLong_AsLong(item);
                Py_DECREF(item);
                if (value == -1 && PyErr_Occurred())
                    /* Integer too big to fit in a C long, bail out */
                    return -1;
                total += value;
            }
            else {
                Py_DECREF(item); /* Discard reference ownership */
            }
        }
        return total;
    }

### Tipos

There are few other data types that play a significant role in the Python/C API; most are simple C types such as `int`, `long`, `double` and `char*`. A few structure types are used to describe static tables used to list the functions exported by a module or the data attributes of a new object type, and another is used to describe the value of a complex number. These will be discussed together with the functions that use them.

## Excepciones

El programador de Python solo necesita lidiar con excepciones si se requiere un manejo específico de errores; las excepciones no manejadas se propagan automáticamente a la persona que llama, luego a la persona que llama, y así sucesivamente, hasta que llegan al intérprete de nivel superior, donde se informan al usuario acompañado de un seguimiento de pila (stack traceback).

Para los programadores de C, sin embargo, la comprobación de errores siempre tiene que ser explícita. Todas las funciones en la API Python/C pueden generar excepciones, a menos que se señale explícitamente en la documentación de una función. En general, cuando una función encuentra un error, establece una excepción, descarta cualquier referencia de objeto que posea y retorna un indicador de error. Si no se documenta lo contrario, este indicador es `NULL` o `-1`, dependiendo del tipo de retorno de la función. Algunas funciones retornan un resultado booleano verdadero/falso, con falso que indica un error. Muy pocas funciones no retornan ningún indicador de error explícito o tienen un valor de retorno ambiguo, y requieren pruebas explícitas de errores con `PyErr_Occurred()`. Estas excepciones siempre se documentan explícitamente.

El estado de excepción se mantiene en el almacenamiento por subproceso (esto es equivalente a usar el almacenamiento global en una aplicación sin subprocesos). Un subproceso puede estar en uno de dos estados: se ha producido una excepción o no. La función `PyErr_Occurred()` puede usarse para verificar esto: retorna una referencia prestada al objeto de tipo de excepción cuando se produce una excepción, y `NULL` de lo contrario. Hay una serie de funciones para establecer el estado de excepción: `PyErr_SetString()` es la función más común (aunque no la más general) para establecer el estado de excepción, y `PyErr_Clear()` borra la excepción estado.

El estado de excepción completo consta de tres objetos (todos los cuales pueden ser `NULL`): el tipo de excepción, el valor de excepción correspondiente y el rastreo. Estos tienen los mismos significados que el resultado de Python de `sys.exc_info()`; sin embargo, no son lo mismo: los objetos Python representan la última excepción manejada por una declaración de Python `try` … `except`, mientras que el estado de excepción de nivel C solo existe mientras se está pasando una excepción entre las funciones de C hasta que llega al bucle principal del intérprete de código de bytes (bytecode) de Python, que se encarga de transferirlo a `sys.exc_info()` y amigos.

Tenga en cuenta que a partir de Python 1.5, la forma preferida y segura de subprocesos para acceder al estado de excepción desde el código de Python es llamar a la función `sys.exc_info()`, que retorna el estado de excepción por subproceso para el código de Python. Además, la semántica de ambas formas de acceder al estado de excepción ha cambiado de modo que una función que detecta una excepción guardará y restaurará el estado de excepción de su hilo para preservar el estado de excepción de su llamador. Esto evita errores comunes en el código de manejo de excepciones causado por una función de aspecto inocente que sobrescribe la excepción que se maneja; También reduce la extensión de vida útil a menudo no deseada para los objetos a los que hacen referencia los marcos de pila en el rastreo.

Como principio general, una función que llama a otra función para realizar alguna tarea debe verificar si la función llamada generó una excepción y, de ser así, pasar el estado de excepción a quien la llama (caller). Debe descartar cualquier referencia de objeto que posea y retornar un indicador de error, pero no debe establecer otra excepción — que sobrescribirá la excepción que se acaba de generar y perderá información importante sobre la causa exacta del error.

Un ejemplo simple de detectar excepciones y pasarlas se muestra en el ejemplo `sum_sequence()` anterior. Sucede que este ejemplo no necesita limpiar ninguna referencia de propiedad cuando detecta un error. La siguiente función de ejemplo muestra algunos errores de limpieza. Primero, para recordar por qué le gusta Python, le mostramos el código Python equivalente:

    def incr_item(dict, key):
        try:
            item = dict[key]
        except KeyError:
            item = 0
        dict[key] = item + 1

Aquí está el código C correspondiente, en todo su esplendor:

    int
    incr_item(PyObject *dict, PyObject *key)
    {
        /* Objects all initialized to NULL for Py_XDECREF */
        PyObject *item = NULL, *const_one = NULL, *incremented_item = NULL;
        int rv = -1; /* Return value initialized to -1 (failure) */

        item = PyObject_GetItem(dict, key);
        if (item == NULL) {
            /* Handle KeyError only: */
            if (!PyErr_ExceptionMatches(PyExc_KeyError))
                goto error;

            /* Clear the error and use zero: */
            PyErr_Clear();
            item = PyLong_FromLong(0L);
            if (item == NULL)
                goto error;
        }
        const_one = PyLong_FromLong(1L);
        if (const_one == NULL)
            goto error;

        incremented_item = PyNumber_Add(item, const_one);
        if (incremented_item == NULL)
            goto error;

        if (PyObject_SetItem(dict, key, incremented_item) < 0)
            goto error;
        rv = 0; /* Success */
        /* Continue with cleanup code */

     error:
        /* Cleanup code, shared by success and failure path */

        /* Use Py_XDECREF() to ignore NULL references */
        Py_XDECREF(item);
        Py_XDECREF(const_one);
        Py_XDECREF(incremented_item);

        return rv; /* -1 for error, 0 for success */
    }

Este ejemplo representa un uso aprobado de la declaración `goto` en C! Ilustra el uso de `PyErr_ExceptionMatches()` y `PyErr_Clear()` para manejar excepciones específicas, y el uso de `Py_XDECREF()` para eliminar referencias propias que pueden ser `NULL` (tenga en cuenta la `'X'`” en el nombre; `Py_DECREF()` se bloqueará cuando se enfrente con una referencia `NULL`). Es importante que las variables utilizadas para contener referencias propias se inicialicen en `NULL` para que esto funcione; Del mismo modo, el valor de retorno propuesto se inicializa a `-1` (falla) y solo se establece en éxito después de que la última llamada realizada sea exitosa.

## Integración de Python

La única tarea importante de la que solo tienen que preocuparse los integradores (a diferencia de los escritores de extensión) del intérprete de Python es la inicialización, y posiblemente la finalización, del intérprete de Python. La mayor parte de la funcionalidad del intérprete solo se puede usar después de que el intérprete se haya inicializado.

La función básica de inicialización es `Py_Initialize()`. Esto inicializa la tabla de módulos cargados y crea los módulos fundamentales `builtins`, `__main__`, y `sys`. También inicializa la ruta de búsqueda del módulo (`sys.path`).

`Py_Initialize()` no establece la «lista de argumentos de script» (`sys.argv`). Si el código de Python necesita esta variable que se ejecutará más adelante, debe establecerse explícitamente con una llamada a `PySys_SetArgvEx(argc, argv, updatepath)` después de la llamada a `Py_Initialize()`.

En la mayoría de los sistemas (en particular, en Unix y Windows, aunque los detalles son ligeramente diferentes), `Py_Initialize()` calcula la ruta de búsqueda del módulo basándose en su mejor estimación de la ubicación del ejecutable del intérprete de Python estándar, suponiendo que la biblioteca de Python se encuentra en una ubicación fija en relación con el ejecutable del intérprete de Python. En particular, busca un directorio llamado `lib/pythonX.Y` relativo al directorio padre donde se encuentra el ejecutable llamado `python` en la ruta de búsqueda del comando shell (la variable de entorno `PATH`).

Por ejemplo, si el ejecutable de Python se encuentra en `/usr/local/bin/python`, se supondrá que las bibliotecas están en `/usr/local/lib/pythonX.Y`. (De hecho, esta ruta particular también es la ubicación «alternativa», utilizada cuando no se encuentra un archivo ejecutable llamado `python` junto con `PATH`.) El usuario puede anular este comportamiento configurando la variable de entorno `PYTHONHOME`, o inserte directorios adicionales delante de la ruta estándar estableciendo `PYTHONPATH`.

La aplicación de integración puede dirigir la búsqueda llamando a `Py_SetProgramName(file)` antes llamando `Py_Initialize()`. Tenga en cuenta que `PYTHONHOME` todavía anula esto y `PYTHONPATH` todavía se inserta frente a la ruta estándar. Una aplicación que requiere un control total debe proporcionar su propia implementación de `Py_GetPath()`, `Py_GetPrefix()`, `Py_GetExecPrefix()`, y `Py_GetProgramFullPath()` (todo definido en `Modules/getpath.c`).

A veces, es deseable «no inicializar» Python. Por ejemplo, la aplicación puede querer comenzar de nuevo (hacer otra llamada a `Py_Initialize()`) o la aplicación simplemente se hace con el uso de Python y quiere liberar memoria asignada por Python. Esto se puede lograr llamando a `Py_FinalizeEx()`. La función `Py_IsInitialized()` retorna verdadero si Python se encuentra actualmente en el estado inicializado. Se proporciona más información sobre estas funciones en un capítulo posterior. Tenga en cuenta que `Py_FinalizeEx()` no libera toda la memoria asignada por el intérprete de Python, por ejemplo, la memoria asignada por los módulos de extensión actualmente no se puede liberar.

## Depuración de compilaciones

Python se puede construir con varios macros para permitir verificaciones adicionales del intérprete y los módulos de extensión. Estas comprobaciones tienden a agregar una gran cantidad de sobrecarga al tiempo de ejecución, por lo que no están habilitadas de forma predeterminada.

Una lista completa de los diversos tipos de compilaciones de depuración se encuentra en el archivo `Misc/SpecialBuilds.txt` en la distribución fuente de Python. Hay compilaciones disponibles que admiten el rastreo de los conteos de referencia, la depuración del asignador de memoria o la creación de perfiles de bajo nivel del bucle principal del intérprete. Solo las compilaciones más utilizadas se describirán en el resto de esta sección.

Compilar el intérprete con el macro `Py_DEBUG` definido produce lo que generalmente se entiende por «una compilación de depuración» de Python. `Py_DEBUG` se habilita en la compilación de Unix agregando `--with-pydebug` al comando `./configure`. También está implícito en la presencia del macro no específico de Python `_DEBUG`. Cuando `Py_DEBUG` está habilitado en la compilación de Unix, la optimización del compilador está deshabilitada.

Además de la depuración del recuento de referencia que se describe a continuación, se realizan las siguientes verificaciones adicionales:

- Se agregan comprobaciones adicionales al asignador de objetos.

- Se agregan verificaciones adicionales al analizador y compilador.

- Las conversiones de tipos hacia abajo (downcasting) de tipos anchos a tipos estrechos se comprueban por pérdida de información.

- Se agregan varias aserciones al diccionario y se establecen implementaciones. Además, el objeto set adquiere un método `test_c_api()`.

- Las comprobaciones de cordura (sanity checks) de los argumentos de entrada se agregan a la creación del marco.

- El almacenamiento para ints se inicializa con un patrón no válido conocido para capturar referencias a dígitos no inicializados.

- El seguimiento de bajo nivel y la comprobación de excepciones adicionales se agregan a la máquina virtual en tiempo de ejecución.

- Se agregan verificaciones adicionales a la implementación de la arena de memoria.

- Se agrega depuración adicional al módulo de hilos.

Puede haber controles adicionales no mencionados aquí.

Definiendo `Py_TRACE_REFS` habilita el rastreo de referencias. Cuando se define, se mantiene una lista circular doblemente vinculada de objetos activos al agregar dos campos adicionales a cada `PyObject`. También se realiza un seguimiento de las asignaciones totales. Al salir, se imprimen todas las referencias existentes. (En modo interactivo, esto sucede después de cada declaración ejecutada por el intérprete). Implicado por `Py_DEBUG`.

Consulte `Misc/SpecialBuilds.txt` en la distribución fuente de Python para obtener información más detallada.