Extensiones Python en C/C++
Extensiones Python en C/C++
Versión 3.12.0
i
3 Incrustar el tiempo de ejecución de CPython en una aplicación más grande 63
3.1 Incrustando Python en otra aplicación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
3.1.1 Incrustación de muy alto nivel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
3.1.2 Más allá de la incrustación de muy alto nivel: una visión general . . . . . . . . . . . . . . . . 64
3.1.3 Incrustación pura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
3.1.4 Extendiendo Python incrustado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
3.1.5 Incrustando Python en C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
3.1.6 Compilar y enlazar bajo sistemas tipo Unix . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
A Glosario 71
C Historia y Licencia 89
C.1 Historia del software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
C.2 Términos y condiciones para acceder o usar Python . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
C.2.1 ACUERDO DE LICENCIA DE PSF PARA PYTHON | lanzamiento | . . . . . . . . . . . . 90
C.2.2 ACUERDO DE LICENCIA DE BEOPEN.COM PARA PYTHON 2.0 . . . . . . . . . . . . 91
C.2.3 ACUERDO DE LICENCIA CNRI PARA PYTHON 1.6.1 . . . . . . . . . . . . . . . . . . 92
C.2.4 ACUERDO DE LICENCIA CWI PARA PYTHON 0.9.0 HASTA 1.2 . . . . . . . . . . . . 93
C.2.5 LICENCIA BSD DE CLÁUSULA CERO PARA CÓDIGO EN EL PYTHON | lanzamiento
| DOCUMENTACIÓN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
C.3 Licencias y reconocimientos para software incorporado . . . . . . . . . . . . . . . . . . . . . . . . . 94
C.3.1 Mersenne Twister . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
C.3.2 Sockets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
C.3.3 Servicios de socket asincrónicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
C.3.4 Gestión de cookies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
C.3.5 Seguimiento de ejecución . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
C.3.6 funciones UUencode y UUdecode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
C.3.7 Llamadas a procedimientos remotos XML . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
C.3.8 test_epoll . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
C.3.9 Seleccionar kqueue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
C.3.10 SipHash24 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
C.3.11 strtod y dtoa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
C.3.12 OpenSSL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
C.3.13 expat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
C.3.14 libffi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
C.3.15 zlib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
C.3.16 cfuhash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
C.3.17 libmpdec . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
C.3.18 Conjunto de pruebas W3C C14N . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
C.3.19 Audioop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Índice 111
ii
Extending and Embedding Python, Versión 3.12.0
Este documento describe cómo escribir módulos en C o C++ para extender el intérprete de Python con nuevos módulos.
Esos módulos no solo pueden definir nuevas funciones sino también nuevos tipos de objetos y sus métodos. El documento
también describe cómo incrustar el intérprete de Python en otra aplicación, para usarlo como un lenguaje de extensión.
Finalmente, muestra cómo compilar y vincular módulos de extensión para que puedan cargarse dinámicamente (en tiempo
de ejecución) en el intérprete, si el sistema operativo subyacente admite esta característica.
Este documento asume conocimientos básicos sobre Python. Para una introducción informal al lenguaje, consulte tutorial-
index. reference-index da una definición más formal del lenguaje. library-index documenta los tipos de objetos, funciones
y módulos existentes (tanto incorporados como escritos en Python) que le dan al lenguaje su amplio rango de aplicaciones.
Para obtener una descripción detallada de toda la API de Python/C, consulte el apartado separado c-api-index.
Índice general 1
Extending and Embedding Python, Versión 3.12.0
2 Índice general
CAPÍTULO 1
This guide only covers the basic tools for creating extensions provided as part of this version of CPython. Third party
tools like Cython, cffi, SWIG and Numba offer both simpler and more sophisticated approaches to creating C and C++
extensions for Python.
Ver también:
Guía del Usuario de Empaquetamiento de Python: Extensiones binarias La Guía del Usuario de Empaquetamien-
to de Python no solo cubre varias herramientas disponibles que simplifican la creación de extensiones binarias, sino
que también discute las diversas razones por las cuales crear un módulo de extensión puede ser deseable en primer
lugar.
3
Extending and Embedding Python, Versión 3.12.0
Esta sección de la guía cubre la creación de extensiones C y C++ sin la ayuda de herramientas de terceros. Está desti-
nado principalmente a los creadores de esas herramientas, en lugar de ser una forma recomendada de crear sus propias
extensiones C.
Es muy fácil agregar nuevos módulos incorporados a Python, si sabe cómo programar en C. Tales como módulos de
extensión pueden hacer dos cosas que no se pueden hacer directamente en Python: pueden implementar nuevos tipos
objetos incorporados, y pueden llamar a funciones de biblioteca C y llamadas de sistema.
Para admitir extensiones, la API de Python (interfaz de programadores de aplicaciones) define un conjunto de funciones,
macros y variables que proporcionan acceso a la mayoría de los aspectos del sistema de tiempo de ejecución de Python.
La API de Python se incorpora en un archivo fuente C incluyendo el encabezado "Python.h".
La compilación de un módulo de extensión depende de su uso previsto, así como de la configuración de su sistema; los
detalles se dan en capítulos posteriores.
Nota: La interfaz de extensión C es específica de CPython, y los módulos de extensión no funcionan en otras imple-
mentaciones de Python. En muchos casos, es posible evitar escribir extensiones C y preservar la portabilidad a otras
implementaciones. Por ejemplo, si su caso de uso es llamar a funciones de biblioteca C o llamadas de sistema, debería
considerar usar el módulo ctypes o la biblioteca cffi en lugar de escribir código personalizado C. Estos módulos le
permiten escribir código Python para interactuar con el código C y son más portátiles entre las implementaciones de
Python que escribir y compilar un módulo de extensión C.
5
Extending and Embedding Python, Versión 3.12.0
Creemos un módulo de extensión llamado spam (la comida favorita de los fanáticos de Monty Python …) y digamos que
queremos crear una interfaz de Python para la función de biblioteca C system()1 . Esta función toma una cadena de
caracteres con terminación nula como argumento y retorna un entero. Queremos que esta función se pueda llamar desde
Python de la siguiente manera:
Comience creando un archivo spammodule.c. (Históricamente, si un módulo se llama spam, el archivo C que contiene
su implementación se llama spammodule.c; si el nombre del módulo es muy largo, como spammify, el nombre del
módulo puede sea solo spammify.c.)
Las dos primeras líneas de nuestro archivo pueden ser:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
que extrae la API de Python (puede agregar un comentario que describa el propósito del módulo y un aviso de copyright
si lo desea).
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 Extracción de parámetros
en funciones de extensión para obtener una descripción de esta macro.
Todos los símbolos visibles para el usuario definidos por Python.h tienen un prefijo Py o PY, excepto los definidos en los
archivos de encabezado estándar. Por conveniencia, y dado que el intérprete de Python los usa ampliamente, "Python.
h" incluye algunos archivos de encabezado estándar: <stdio.h>, <string.h>, <errno.h>, y <stdlib.h>. Si
el último archivo de encabezado no existe en su sistema, declara las funciones malloc(), free() y realloc()
directamente.
Lo siguiente que agregamos a nuestro archivo de módulo es la función C que se llamará cuando se evalúe la expresión
Python spam.system(string) (veremos en breve cómo termina siendo llamado):
static PyObject *
spam_system(PyObject *self, PyObject *args)
{
const char *command;
int sts;
Hay una traducción directa de la lista de argumentos en Python (por ejemplo, la única expresión "ls -l") a los argu-
mentos pasados a la función C. La función C siempre tiene dos argumentos, llamados convencionalmente self y args.
El argumento self apunta al objeto del módulo para funciones a nivel de módulo; para un método apuntaría a la instancia
del objeto.
1 Ya existe una interfaz para esta función en el módulo estándar os — se eligió como un ejemplo simple y directo.
El argumento args será un puntero a un objeto de tupla de Python que contiene los argumentos. Cada elemento de la tupla
corresponde a un argumento en la lista de argumentos de la llamada. Los argumentos son objetos de Python — para hacer
algo con ellos en nuestra función C tenemos que convertirlos a valores C. La función PyArg_ParseTuple() en la
API de Python verifica los tipos de argumento y los convierte a valores C. Utiliza una cadena de plantilla para determinar
los tipos requeridos de los argumentos, así como los tipos de las variables C en las que almacenar los valores convertidos.
Más sobre esto más tarde.
PyArg_ParseTuple() retorna verdadero (distinto de cero) si todos los argumentos tienen el tipo correcto y sus
componentes se han almacenado en las variables cuyas direcciones se pasan. Retorna falso (cero) si se pasó una lista de
argumentos no válidos. En el último caso, también genera una excepción apropiada para que la función de llamada pueda
retornar NULL inmediatamente (como vimos en el ejemplo).
Una convención importante en todo el intérprete de Python es la siguiente: cuando una función falla, debe establecer una
condición de excepción y retornar un valor de error (generalmente -1 o un puntero NULL). La información de excepción
se almacena en tres miembros del estado del subproceso del intérprete. Estos son NULL si no hay excepción. De lo
contrario, son los equivalentes en C de los miembros de la tupla Python retornada por sys.exc_info(). Estos son el
tipo de excepción, la instancia de excepción y un objeto de rastreo. Es importante conocerlos para comprender cómo se
transmiten los errores.
La API de Python define una serie de funciones para establecer varios tipos de excepciones.
El más común es PyErr_SetString(). Sus argumentos son un objeto de excepción y una cadena C. El objeto de
excepción suele ser un objeto predefinido como PyExc_ZeroDivisionError. La cadena C indica la causa del error
y se convierte en un objeto de cadena Python y se almacena como el «valor asociado» de la excepción.
Otra función útil es PyErr_SetFromErrno(), que solo toma un argumento de excepción y construye el valor asociado
mediante la inspección de la variable global errno. La función más general es PyErr_SetObject(), que toma dos
argumentos de objeto, la excepción y su valor asociado. No necesita Py_INCREF() los objetos pasados a cualquiera de
estas funciones.
Puede probar de forma no destructiva si se ha establecido una excepción con PyErr_Occurred(). Esto retorna
el objeto de excepción actual o NULL si no se ha producido ninguna excepción. Normalmente no necesita llamar a
PyErr_Occurred() para ver si se produjo un error en una llamada a la función, ya que debería poder distinguir el
valor de retorno.
Cuando una función f que llama a otra función g detecta que esta última falla, f debería retornar un valor de error
(normalmente NULL o -1). Debería no llamar a una de las funciones PyErr_* — g ya ha llamado a una. Se supone
que la persona que llama a f también retornará una indicación de error a su persona que la llama, nuevamente sin llama
a PyErr_*, y así sucesivamente — la función que lo detectó primero ya informó la causa más detallada del error. Una
vez que el error llega al bucle principal del intérprete de Python, este aborta el código de Python que se está ejecutando
actualmente e intenta encontrar un controlador de excepciones especificado por el programador de Python.
(Hay situaciones en las que un módulo puede dar un mensaje de error más detallado llamando a otra función PyErr_*,
y en tales casos está bien hacerlo. Sin embargo, como regla general, esto no es necesario y puede causar que se pierda
información sobre la causa del error: la mayoría de las operaciones pueden fallar por una variedad de razones).
Para ignorar una excepción establecida por una llamada de función que falló, la condición de excepción debe borrarse
explícitamente llamando a PyErr_Clear(). La única vez que el código C debe llamar PyErr_Clear() es si no
quiere pasar el error al intérprete pero quiere manejarlo completamente por sí mismo (posiblemente probando algo más
o pretendiendo que nada salió mal) )
Cada llamada fallida a malloc() debe convertirse en una excepción — la persona que llama directamente de
malloc() (o realloc()) debe llamar PyErr_NoMemory() y retorna un indicador de falla en sí mismo. To-
das las funciones de creación de objetos (por ejemplo, PyLong_FromLong()) ya hacen esto, por lo que esta nota solo
es relevante para aquellos que llaman malloc() directamente.
También tenga en cuenta que, con la importante excepción de PyArg_ParseTuple() y sus amigos, las funciones
que retornan un estado entero generalmente retornan un valor positivo o cero para el éxito y -1 para el fracaso, como las
llamadas al sistema Unix.
Finalmente, tenga cuidado de limpiar la basura (haciendo Py_XDECREF() o Py_DECREF() requiere objetos que ya
ha creado) cuando retorna un indicador de error!
The choice of which exception to raise is entirely yours. There are predeclared C objects corresponding to all built-in
Python exceptions, such as PyExc_ZeroDivisionError, which you can use directly. Of course, you should choose
exceptions wisely — don’t use PyExc_TypeError to mean that a file couldn’t be opened (that should probably be
PyExc_OSError). If something’s wrong with the argument list, the PyArg_ParseTuple() function usually raises
PyExc_TypeError. If you have an argument whose value must be in a particular range or must satisfy other conditions,
PyExc_ValueError is appropriate.
También puede definir una nueva excepción que sea exclusiva de su módulo. Para esto, generalmente declara una variable
de objeto estático al comienzo de su archivo:
static PyObject *SpamError;
and initialize it in your module’s initialization function (PyInit_spam()) with an exception object:
PyMODINIT_FUNC
PyInit_spam(void)
{
PyObject *m;
m = PyModule_Create(&spammodule);
if (m == NULL)
return NULL;
return m;
}
Note that the Python name for the exception object is spam.error. The PyErr_NewException() function may
create a class with the base class being Exception (unless another class is passed in instead of NULL), described in
bltin-exceptions.
Note also that the SpamError variable retains a reference to the newly created exception class; this is intentional! Since
the exception could be removed from the module by external code, an owned reference to the class is needed to ensure
that it will not be discarded, causing SpamError to become a dangling pointer. Should it become a dangling pointer, C
code which raises the exception could cause a core dump or other unintended side effects.
We discuss the use of PyMODINIT_FUNC as a function return type later in this sample.
The spam.error exception can be raised in your extension module using a call to PyErr_SetString() as shown
below:
static PyObject *
spam_system(PyObject *self, PyObject *args)
{
(continué en la próxima página)
Volviendo a nuestra función de ejemplo, ahora debería poder comprender esta declaración:
It returns NULL (the error indicator for functions returning object pointers) if an error is detected in the argument list,
relying on the exception set by PyArg_ParseTuple(). Otherwise the string value of the argument has been copied
to the local variable command. This is a pointer assignment and you are not supposed to modify the string to which it
points (so in Standard C, the variable command should properly be declared as const char *command).
La siguiente declaración es una llamada a la función Unix system(), pasándole la cadena que acabamos de obtener de
PyArg_ParseTuple():
sts = system(command);
Our spam.system() function must return the value of sts as a Python object. This is done using the function
PyLong_FromLong().
return PyLong_FromLong(sts);
En este caso, retornará un objeto entero. (Sí, ¡incluso los enteros son objetos en el montículo (heap) en Python!)
Si tiene una función C que no retorna ningún argumento útil (una función que retorna void), la función de Pyt-
hon correspondiente debe retornar None. Necesita esta expresión para hacerlo (que se implementa mediante la macro
Py_RETURN_NONE):
Py_INCREF(Py_None);
return Py_None;
Py_None es el nombre C para el objeto especial de Python None. Es un objeto genuino de Python en lugar de un puntero
NULL, que significa «error» en la mayoría de los contextos, como hemos visto.
I promised to show how spam_system() is called from Python programs. First, we need to list its name and address
in a «method table»:
Tenga en cuenta la tercera entrada (METH_VARARGS). Esta es una bandera que le dice al intérprete la convención de
llamada que se utilizará para la función C. Normalmente debería ser siempre METH_VARARGS o METH_VARARGS |
METH_KEYWORDS; un valor de 0 significa que se usa una variante obsoleta de PyArg_ParseTuple().
Cuando se usa solo METH_VARARGS, la función debe esperar que los parámetros a nivel de Python se pasen como una
tupla aceptable para el análisis mediante PyArg_ParseTuple(); A continuación se proporciona más información
sobre esta función.
The METH_KEYWORDS bit may be set in the third field if keyword arguments should be passed to the function. In
this case, the C function should accept a third PyObject * parameter which will be a dictionary of keywords. Use
PyArg_ParseTupleAndKeywords() to parse the arguments to such a function.
La tabla de métodos debe ser referenciada en la estructura de definición del módulo:
This structure, in turn, must be passed to the interpreter in the module’s initialization function. The initialization function
must be named PyInit_name(), where name is the name of the module, and should be the only non-static item
defined in the module file:
PyMODINIT_FUNC
PyInit_spam(void)
{
return PyModule_Create(&spammodule);
}
Note that PyMODINIT_FUNC declares the function as PyObject * return type, declares any special linkage decla-
rations required by the platform, and for C++ declares the function as extern "C".
When the Python program imports module spam for the first time, PyInit_spam() is called. (See below for comments
about embedding Python.) It calls PyModule_Create(), which returns a module object, and inserts built-in function
objects into the newly created module based upon the table (an array of PyMethodDef structures) found in the module
definition. PyModule_Create() returns a pointer to the module object that it creates. It may abort with a fatal error
for certain errors, or return NULL if the module could not be initialized satisfactorily. The init function must return the
module object to its caller, so that it then gets inserted into sys.modules.
When embedding Python, the PyInit_spam() function is not called automatically unless there’s an entry in the
PyImport_Inittab table. To add the module to the initialization table, use PyImport_AppendInittab(),
optionally followed by an import of the module:
int
main(int argc, char *argv[])
{
wchar_t *program = Py_DecodeLocale(argv[0], NULL);
if (program == NULL) {
fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
exit(1);
}
...
PyMem_RawFree(program);
return 0;
}
Nota: Eliminar entradas de sys.modules o importar módulos compilados en múltiples intérpretes dentro de un
proceso (o seguir un fork() sin una intervención exec()) puede crear problemas para algunas extensiones de módulos.
Los autores de módulos de extensiones deben tener precaución al inicializar estructuras de datos internas.
Se incluye un módulo de ejemplo más sustancial en la distribución fuente de Python como Modules/xxmodule.c.
Este archivo puede usarse como plantilla o simplemente leerse como ejemplo.
Nota: A diferencia de nuestro ejemplo de spam, xxmodule usa inicialización de múltiples fases (nuevo en Python 3.5),
donde se retorna una estructura PyModuleDef de PyInit_spam, y la creación del módulo se deja al maquinaria de
importación. Para obtener detalles sobre la inicialización múltiples fases, consulte PEP 489.
Hay dos cosas más que hacer antes de que pueda usar su nueva extensión: compilarla y vincularla con el sistema Pyt-
hon. Si usa carga dinámica, los detalles pueden depender del estilo de carga dinámica que usa su sistema; Para obtener
más información al respecto, consulte los capítulos sobre la creación de módulos de extensión (capítulo Construyendo
extensiones C y C++) e información adicional que se refiere solo a la construcción en Windows (capítulo Creación de
extensiones C y C++ en Windows).
Si no puede utilizar la carga dinámica, o si desea que su módulo sea una parte permanente del intérpre-
te de Python, tendrá que cambiar la configuración (setup) y reconstruir el intérprete. Afortunadamente, es-
to es muy simple en Unix: simplemente coloque su archivo (spammodule.c por ejemplo) en el direc-
torio Modules/ ` de una distribución fuente desempaquetada, agregue una línea al
archivo :file:`Modules/Setup.local que describe su archivo:
spam spammodule.o
y reconstruya el intérprete ejecutando make en el directorio de nivel superior. También puede ejecutar make en el
subdirectorio Modules/, pero primero debe reconstruir Makefile ejecutando “make Makefile”. (Esto es necesario
cada vez que cambia el archivo Configuración).
Si su módulo requiere bibliotecas adicionales para vincular, también se pueden enumerar en la línea del archivo de con-
figuración, por ejemplo:
Hasta ahora nos hemos concentrado en hacer que las funciones de C puedan llamarse desde Python. Lo contrario también
es útil: llamar a las funciones de Python desde C. Este es especialmente el caso de las bibliotecas que admiten las llamadas
funciones de «retrollamada». Si una interfaz C utiliza retrollamadas, el Python equivalente a menudo necesita propor-
cionar un mecanismo de retrollamada al programador de Python; la implementación requerirá llamar a las funciones de
retrollamada de Python desde una retrollamada en C. Otros usos también son imaginables.
Afortunadamente, el intérprete de Python se llama fácilmente de forma recursiva, y hay una interfaz estándar para llamar
a una función de Python. (No me detendré en cómo llamar al analizador Python con una cadena particular como entrada
— si está interesado, eche un vistazo a la implementación de la opción de línea de comando -c en Modules/main.c
del código fuente de Python.)
Llamar a una función de Python es fácil. Primero, el programa Python debe de alguna manera pasar el objeto de función
Python. Debe proporcionar una función (o alguna otra interfaz) para hacer esto. Cuando se llama a esta función, guarde
un puntero en el objeto de la función Python (tenga cuidado de usar Py_INCREF()) En una variable global — o donde
mejor le parezca. Por ejemplo, la siguiente función podría ser parte de una definición de módulo:
static PyObject *
my_set_callback(PyObject *dummy, PyObject *args)
{
PyObject *result = NULL;
PyObject *temp;
This function must be registered with the interpreter using the METH_VARARGS flag; this is described in section La
tabla de métodos del módulo y la función de inicialización. The PyArg_ParseTuple() function and its arguments
are documented in section Extracción de parámetros en funciones de extensión.
Las macros Py_XINCREF() y Py_XDECREF() incrementan/disminuyen el recuento de referencia de un objeto y son
seguros en presencia de punteros NULL (pero tenga en cuenta que temp no lo hará ser NULL en este contexto). Más
información sobre ellos en la sección Conteo de referencias.
Más tarde, cuando es hora de llamar a la función, llama a la función C PyObject_CallObject(). Esta función
tiene dos argumentos, ambos punteros a objetos arbitrarios de Python: la función Python y la lista de argumentos. La
lista de argumentos siempre debe ser un objeto de tupla, cuya longitud es el número de argumentos. Para llamar a la
función Python sin argumentos, pase NULL o una tupla vacía; para llamarlo con un argumento, pasa una tupla singleton.
Py_BuildValue() retorna una tupla cuando su cadena de formato consta de cero o más códigos de formato entre
paréntesis. Por ejemplo:
int arg;
PyObject *arglist;
PyObject *result;
...
arg = 123;
...
/* Time to call the callback */
arglist = Py_BuildValue("(i)", arg);
result = PyObject_CallObject(my_callback, arglist);
Py_DECREF(arglist);
PyObject_CallObject() retorna un puntero de objeto Python: este es el valor de retorno de la función Python.
PyObject_CallObject() es «recuento-referencia-neutral» con respecto a sus argumentos. En el ejemplo, se creó
una nueva tupla para servir como lista de argumentos, a la cual se le llama Py_DECREF() inmediatamente después de
la llamada PyObject_CallObject().
El valor de retorno de PyObject_CallObject() es «nuevo»: o bien es un objeto nuevo o es un objeto existente cuyo
recuento de referencias se ha incrementado. Por lo tanto, a menos que desee guardarlo en una variable global, debería de
alguna manera Py_DECREF() el resultado, incluso (¡especialmente!) Si no está interesado en su valor.
Sin embargo, antes de hacer esto, es importante verificar que el valor de retorno no sea NULL. Si es así, la función
de Python terminó generando una excepción. Si el código C que llamó PyObject_CallObject() se llama desde
Python, ahora debería retornar una indicación de error a su llamador de Python, para que el intérprete pueda imprimir
un seguimiento de la pila, o el código de Python que llama puede manejar la excepción. Si esto no es posible o deseable,
la excepción se debe eliminar llamando a PyErr_Clear(). Por ejemplo:
if (result == NULL)
return NULL; /* Pass error back */
...use result...
Py_DECREF(result);
Dependiendo de la interfaz deseada para la función de retrollamada de Python, es posible que también deba proporcionar
una lista de argumentos para PyObject_CallObject(). En algunos casos, el programa Python también proporciona
la lista de argumentos, a través de la misma interfaz que especificó la función de retrollamada. Luego se puede guardar
y usar de la misma manera que el objeto de función. En otros casos, puede que tenga que construir una nueva tupla para
pasarla como lista de argumentos. La forma más sencilla de hacer esto es llamar a Py_BuildValue(). Por ejemplo,
si desea pasar un código de evento integral, puede usar el siguiente código:
PyObject *arglist;
...
arglist = Py_BuildValue("(l)", eventcode);
result = PyObject_CallObject(my_callback, arglist);
Py_DECREF(arglist);
if (result == NULL)
return NULL; /* Pass error back */
/* Here maybe use the result */
Py_DECREF(result);
El argumento arg debe ser un objeto de tupla que contenga una lista de argumentos pasada de Python a una función C.
El argumento format debe ser una cadena de formato, cuya sintaxis se explica en arg-parsing en el Manual de referencia
de la API de Python/C. Los argumentos restantes deben ser direcciones de variables cuyo tipo está determinado por la
cadena de formato.
Tenga en cuenta que si bien PyArg_ParseTuple() verifica que los argumentos de Python tengan los tipos requeridos,
no puede verificar la validez de las direcciones de las variables C pasadas a la llamada: si comete errores allí, su código
probablemente se bloqueará o al menos sobrescribir bits aleatorios en la memoria. ¡Así que ten cuidado!
Tenga en cuenta que las referencias de objetos de Python que se proporcionan a quien llama son referencias prestadas
(borrowed); ¡no disminuya su recuento de referencias!
Algunas llamadas de ejemplo:
#define PY_SSIZE_T_CLEAN /* Make "s#" use Py_ssize_t rather than int. */
#include <Python.h>
int ok;
int i, j;
long k, l;
const char *s;
Py_ssize_t size;
{
const char *file;
const char *mode = "r";
int bufsize = 0;
ok = PyArg_ParseTuple(args, "s|si", &file, &mode, &bufsize);
/* A string, and optionally another string and an integer */
/* Possible Python calls:
f('spam')
f('spam', 'w')
f('spam', 'wb', 100000) */
}
{
int left, top, right, bottom, h, v;
ok = PyArg_ParseTuple(args, "((ii)(ii))(ii)",
&left, &top, &right, &bottom, &h, &v);
/* A rectangle and a point */
/* Possible Python call:
f(((0, 0), (400, 300)), (10, 10)) */
}
{
Py_complex c;
ok = PyArg_ParseTuple(args, "D:myfunction", &c);
/* a complex, also providing a function name for errors */
/* Possible Python call: myfunction(1+2j) */
}
Los parámetros arg y format son idénticos a los de la función PyArg_ParseTuple(). El parámetro kwdict es el dic-
cionario de palabras clave recibidas como tercer parámetro del tiempo de ejecución de Python. El parámetro kwlist es una
lista de cadenas terminadas en NULL que identifican los parámetros; los nombres se corresponden con la información de
tipo de format de izquierda a derecha. En caso de éxito, PyArg_ParseTupleAndKeywords() retorna verdadero;
de lo contrario, retorna falso y genera una excepción apropiada.
Nota: ¡Las tuplas anidadas no se pueden analizar al usar argumentos de palabras clave! Los parámetros de palabras clave
pasados que no están presentes en la kwlist provocarán que se genere TypeError.
Aquí hay un módulo de ejemplo que usa palabras clave, basado en un ejemplo de Geoff Philbrick ([email protected]):
#define PY_SSIZE_T_CLEAN /* Make "s#" use Py_ssize_t rather than int. */
#include <Python.h>
static PyObject *
keywdarg_parrot(PyObject *self, PyObject *args, PyObject *keywds)
{
int voltage;
const char *state = "a stiff";
const char *action = "voom";
const char *type = "Norwegian Blue";
Py_RETURN_NONE;
}
PyMODINIT_FUNC
PyInit_keywdarg(void)
{
return PyModule_Create(&keywdargmodule);
}
Reconoce un conjunto de unidades de formato similares a las reconocidas por PyArg_ParseTuple(), pero los ar-
gumentos (que son de entrada a la función, no de salida) no deben ser punteros, solo valores. Retorna un nuevo objeto
Python, adecuado para regresar de una función C llamada desde Python.
Una diferencia con PyArg_ParseTuple(): mientras que este último requiere que su primer argumento sea una tupla
(ya que las listas de argumentos de Python siempre se representan como tuplas internamente), Py_BuildValue() no
siempre construye una tupla . Construye una tupla solo si su cadena de formato contiene dos o más unidades de formato.
Si la cadena de formato está vacía, retorna None; si contiene exactamente una unidad de formato, retorna el objeto que
describa esa unidad de formato. Para forzarlo a retornar una tupla de tamaño 0 o uno, agregar paréntesis a la cadena de
formato.
Ejemplos (a la izquierda la llamada, a la derecha el valor de Python resultante):
Py_BuildValue("") None
Py_BuildValue("i", 123) 123
Py_BuildValue("iii", 123, 456, 789) (123, 456, 789)
Py_BuildValue("s", "hello") 'hello'
Py_BuildValue("y", "hello") b'hello'
Py_BuildValue("ss", "hello", "world") ('hello', 'world')
Py_BuildValue("s#", "hello", 4) 'hell'
Py_BuildValue("y#", "hello", 4) b'hell'
Py_BuildValue("()") ()
Py_BuildValue("(i)", 123) (123,)
Py_BuildValue("(ii)", 123, 456) (123, 456)
Py_BuildValue("(i,i)", 123, 456) (123, 456)
Py_BuildValue("[i,i]", 123, 456) [123, 456]
Py_BuildValue("{s:i,s:i}",
"abc", 123, "def", 456) {'abc': 123, 'def': 456}
Py_BuildValue("((ii)(ii)) (ii)",
1, 2, 3, 4, 5, 6) (((1, 2), (3, 4)), (5, 6))
Hay dos macros, Py_INCREF(x) y Py_DECREF(x), que manejan el incremento y la disminución del recuento de
referencias. Py_DECREF() también libera el objeto cuando el recuento llega a cero. Por flexibilidad, no llama a free()
directamente — más bien, realiza una llamada a través de un puntero de función en el objeto type object. Para este propósito
(y otros), cada objeto también contiene un puntero a su objeto de tipo.
La gran pregunta ahora permanece: ¿cuándo usar Py_INCREF(x) y Py_DECREF(x)? Primero introduzcamos algu-
nos términos. Nadie «posee» un objeto; sin embargo, puede poseer una referencia a un objeto. El recuento de referencias
de un objeto ahora se define como el número de referencias que posee. El propietario de una referencia es responsable de
llamar a Py_DECREF() cuando la referencia ya no es necesaria. La propiedad de una referencia puede ser transferida.
Hay tres formas de deshacerse de una referencia de propiedad: pasarla, almacenarla o llamar a Py_DECREF(). Olvidar
deshacerse de una referencia de propiedad crea una pérdida de memoria.
También es posible tomar prestada2 una referencia a un objeto. El prestatario de una referencia no debe llamar a
Py_DECREF(). El prestatario no debe retener el objeto por más tiempo que el propietario del cual fue prestado. El
uso de una referencia prestada después de que el propietario la haya eliminado corre el riesgo de usar memoria liberada
y debe evitarse por completo3 .
La ventaja de pedir prestado sobre tener una referencia es que no necesita ocuparse de disponer de la referencia en todas
las rutas posibles a través del código — en otras palabras, con una referencia prestada no corre el riesgo de fugas cuando
se toma una salida prematura. La desventaja de pedir prestado sobre la posesión es que hay algunas situaciones sutiles en
las que, en un código aparentemente correcto, una referencia prestada se puede usar después de que el propietario del que
se tomó prestado la haya eliminado.
Una referencia prestada se puede cambiar en una referencia de propiedad llamando a Py_INCREF(). Esto no afecta
el estado del propietario del cual se tomó prestada la referencia: crea una nueva referencia de propiedad y otorga res-
ponsabilidades completas al propietario (el nuevo propietario debe disponer de la referencia correctamente, así como el
propietario anterior).
Reglas de propiedad
Cuando una referencia de objeto se pasa dentro o fuera de una función, es parte de la especificación de la interfaz de la
función si la propiedad se transfiere con la referencia o no.
La mayoría de las funciones que retornan una referencia a un objeto pasan de propiedad con la referencia. En particular,
todas las funciones cuya función es crear un nuevo objeto, como PyLong_FromLong() y Py_BuildValue(),
pasan la propiedad al receptor. Incluso si el objeto no es realmente nuevo, aún recibirá la propiedad de una nueva refe-
rencia a ese objeto. Por ejemplo, PyLong_FromLong() mantiene un caché de valores populares y puede retornar una
referencia a un elemento en caché.
Muchas funciones que extraen objetos de otros objetos también transfieren la propiedad con la referencia,
por ejemplo PyObject_GetAttrString(). Sin embargo, la imagen es menos clara aquí, ya que algunas
rutinas comunes son excepciones: PyTuple_GetItem(), PyList_GetItem(), PyDict_GetItem(), y
PyDict_GetItemString() todas las referencias retornadas que tomaste prestadas de la tupla, lista o diccionario.
La función PyImport_AddModule() también retorna una referencia prestada, aunque en realidad puede crear el
objeto que retorna: esto es posible porque una referencia de propiedad del objeto se almacena en sys.modules.
Cuando pasa una referencia de objeto a otra función, en general, la función toma prestada la referencia de usted —
si necesita almacenarla, usará Py_INCREF() para convertirse en un propietario independiente. Hay exactamente dos
excepciones importantes a esta regla: PyTuple_SetItem() y PyList_SetItem(). Estas funciones se hacen
cargo de la propiedad del artículo que se les pasa, ¡incluso si fallan! (Tenga en cuenta que PyDict_SetItem() y sus
amigos no se hacen cargo de la propiedad — son «normales»)
2 La metáfora de «pedir prestado» una referencia no es completamente correcta: el propietario todavía tiene una copia de la referencia.
3 ¡Comprobar que el recuento de referencia es al menos 1 no funciona — el recuento de referencia en sí podría estar en la memoria liberada y, por
lo tanto, puede reutilizarse para otro objeto!
Cuando se llama a una función C desde Python, toma de la persona que llama referencias a sus argumentos. Quien llama
posee una referencia al objeto, por lo que la vida útil de la referencia prestada está garantizada hasta que la función
regrese. Solo cuando dicha referencia prestada debe almacenarse o transmitirse, debe convertirse en una referencia propia
llamando a Py_INCREF().
La referencia de objeto retornada desde una función C que se llama desde Python debe ser una referencia de propiedad:
la propiedad se transfiere de la función a su llamador.
Hielo delgado
Hay algunas situaciones en las que el uso aparentemente inofensivo de una referencia prestada puede generar problemas.
Todo esto tiene que ver con invocaciones implícitas del intérprete, lo que puede hacer que el propietario de una referencia
se deshaga de él.
El primer y más importante caso que debe conocer es el uso de Py_DECREF() en un objeto no relacionado mientras
toma prestada una referencia a un elemento de la lista. Por ejemplo:
void
bug(PyObject *list)
{
PyObject *item = PyList_GetItem(list, 0);
PyList_SetItem(list, 1, PyLong_FromLong(0L));
PyObject_Print(item, stdout, 0); /* BUG! */
}
Esta función primero toma prestada una referencia a list[0], luego reemplaza list[1] con el valor 0, y finalmente
imprime la referencia prestada. Parece inofensivo, ¿verdad? ¡Pero no lo es!
Let’s follow the control flow into PyList_SetItem(). The list owns references to all its items, so when item 1 is
replaced, it has to dispose of the original item 1. Now let’s suppose the original item 1 was an instance of a user-defined
class, and let’s further suppose that the class defined a __del__() method. If this class instance has a reference count
of 1, disposing of it will call its __del__() method.
Since it is written in Python, the __del__() method can execute arbitrary Python code. Could it perhaps do something
to invalidate the reference to item in bug()? You bet! Assuming that the list passed into bug() is accessible to
the __del__() method, it could execute a statement to the effect of del list[0], and assuming this was the last
reference to that object, it would free the memory associated with it, thereby invalidating item.
La solución, una vez que conoce el origen del problema, es fácil: incremente temporalmente el recuento de referencia. La
versión correcta de la función dice:
void
no_bug(PyObject *list)
{
PyObject *item = PyList_GetItem(list, 0);
Py_INCREF(item);
PyList_SetItem(list, 1, PyLong_FromLong(0L));
PyObject_Print(item, stdout, 0);
Py_DECREF(item);
}
This is a true story. An older version of Python contained variants of this bug and someone spent a considerable amount
of time in a C debugger to figure out why his __del__() methods would fail…
El segundo caso de problemas con una referencia prestada es una variante que involucra hilos. Normalmente, va-
rios hilos en el intérprete de Python no pueden interponerse entre sí, porque hay un bloqueo global que protege to-
do el espacio de objetos de Python. Sin embargo, es posible liberar temporalmente este bloqueo usando la macro
Py_BEGIN_ALLOW_THREADS, y volver a adquirirlo usando Py_END_ALLOW_THREADS. Esto es común al blo-
quear las llamadas de E/S, para permitir que otros subprocesos usen el procesador mientras esperan que se complete la
E/S. Obviamente, la siguiente función tiene el mismo problema que la anterior:
void
bug(PyObject *list)
{
PyObject *item = PyList_GetItem(list, 0);
Py_BEGIN_ALLOW_THREADS
...some blocking I/O call...
Py_END_ALLOW_THREADS
PyObject_Print(item, stdout, 0); /* BUG! */
}
Punteros NULL
En general, las funciones que toman referencias de objetos como argumentos no esperan que les pase los punteros NULL,
y volcará el núcleo (o causará volcados de núcleo posteriores) si lo hace. Las funciones que retornan referencias a objetos
generalmente retornan NULL solo para indicar que ocurrió una excepción. La razón para no probar los argumentos NULL
es que las funciones a menudo pasan los objetos que reciben a otra función — si cada función probara NULL, habría
muchas pruebas redundantes y el código correría más lentamente.
Es mejor probar NULL solo en «source:» cuando se recibe un puntero que puede ser NULL, por ejemplo, de malloc()
o de una función que puede plantear una excepción.
Las macros Py_INCREF() y Py_DECREF() no comprueban los punteros NULL — sin embargo, sus variantes
Py_XINCREF() y Py_XDECREF() lo hacen.
Las macros para verificar un tipo de objeto en particular (Pytype_Check()) no verifican los punteros NULL —
nuevamente, hay mucho código que llama a varios de estos en una fila para probar un objeto contra varios tipos esperados
diferentes, y esto generaría pruebas redundantes. No hay variantes con comprobación NULL.
El mecanismo de llamada a la función C garantiza que la lista de argumentos pasada a las funciones C (args en los
ejemplos) nunca sea NULL — de hecho, garantiza que siempre sea una tupla4 .
Es un error grave dejar que un puntero NULL «escape» al usuario de Python.
Es posible escribir módulos de extensión en C++. Se aplican algunas restricciones. Si el compilador de C compila y vincula
el programa principal (el intérprete de Python), no se pueden usar objetos globales o estáticos con constructores. Esto no
es un problema si el programa principal está vinculado por el compilador de C++. Las funciones que serán llamadas por el
intérprete de Python (en particular, las funciones de inicialización del módulo) deben declararse usando extern "C".
No es necesario encerrar los archivos de encabezado de Python en extern "C" {...} — ya usan este formulario si
el símbolo __cplusplus está definido (todos los compiladores recientes de C++ definen este símbolo) .
4 Estas garantías no se cumplen cuando utiliza la convención de llamadas de estilo «antiguo», que todavía se encuentra en muchos códigos existentes.
Muchos módulos de extensión solo proporcionan nuevas funciones y tipos para ser utilizados desde Python, pero a veces
el código en un módulo de extensión puede ser útil para otros módulos de extensión. Por ejemplo, un módulo de extensión
podría implementar un tipo de «colección» que funciona como listas sin orden. Al igual que el tipo de lista Python estándar
tiene una API C que permite a los módulos de extensión crear y manipular listas, este nuevo tipo de colección debe tener
un conjunto de funciones C para la manipulación directa desde otros módulos de extensión.
A primera vista, esto parece fácil: simplemente escriba las funciones (sin declararlas static, por supuesto), proporcione
un archivo de encabezado apropiado y documente la API de C. Y, de hecho, esto funcionaría si todos los módulos de
extensión siempre estuvieran vinculados estáticamente con el intérprete de Python. Sin embargo, cuando los módulos
se usan como bibliotecas compartidas, los símbolos definidos en un módulo pueden no ser visibles para otro módulo.
Los detalles de visibilidad dependen del sistema operativo; algunos sistemas usan un espacio de nombres global para el
intérprete de Python y todos los módulos de extensión (Windows, por ejemplo), mientras que otros requieren una lista
explícita de símbolos importados en el momento del enlace del módulo (AIX es un ejemplo) u ofrecen una variedad
de estrategias diferentes (la mayoría Unices). E incluso si los símbolos son visibles a nivel mundial, ¡el módulo cuyas
funciones uno desea llamar podría no haberse cargado todavía!
Por lo tanto, la portabilidad requiere no hacer suposiciones sobre la visibilidad del símbolo. Esto significa que todos los
símbolos en los módulos de extensión deben declararse static, excepto la función de inicialización del módulo, para
evitar conflictos de nombres con otros módulos de extensión (como se discutió en la sección La tabla de métodos del
módulo y la función de inicialización). Y significa que los símbolos que deberían ser accesibles desde otros módulos de
extensión deben exportarse de una manera diferente.
Python proporciona un mecanismo especial para pasar información de nivel C (punteros) de un módulo de extensión a
otro: cápsulas. Una cápsula es un tipo de datos de Python que almacena un puntero (void*). Solo se puede crear y
acceder a las cápsulas a través de su API C, pero se pueden pasar como cualquier otro objeto de Python. En particular,
se pueden asignar a un nombre en el espacio de nombres de un módulo de extensión. Otros módulos de extensión pueden
importar este módulo, recuperar el valor de este nombre y luego recuperar el puntero de la Cápsula.
Hay muchas formas en que las Cápsulas se pueden usar para exportar la API de C de un módulo de extensión. Cada
función podría tener su propia cápsula, o todos los punteros de API C podrían almacenarse en una matriz cuya dirección
se publica en una cápsula. Y las diversas tareas de almacenamiento y recuperación de los punteros se pueden distribuir
de diferentes maneras entre el módulo que proporciona el código y los módulos del cliente.
Cualquiera que sea el método que elija, es importante nombrar correctamente sus Cápsulas. La función
PyCapsule_New() toma un parámetro de nombre (const char*); se le permite pasar un nombre NULL, pero
le recomendamos encarecidamente que especifique un nombre. Las Cápsulas correctamente nombradas brindan un gra-
do de seguridad de tipo de tiempo de ejecución; no hay una forma factible de distinguir una Cápsula sin nombre de
otra.
En particular, las cápsulas utilizadas para exponer las API de C deben recibir un nombre siguiendo esta convención:
modulename.attributename
La función de conveniencia PyCapsule_Import() facilita la carga de una API C proporcionada a través de una
cápsula, pero solo si el nombre de la cápsula coincide con esta convención. Este comportamiento brinda a los usuarios de
C API un alto grado de certeza de que la Cápsula que cargan contiene la API de C correcta.
El siguiente ejemplo demuestra un enfoque que pone la mayor parte de la carga sobre el escritor del módulo de exportación,
que es apropiado para los módulos de biblioteca de uso común. Almacena todos los punteros de la API de C (¡solo uno
en el ejemplo!) en un arreglo de punteros void que se convierte en el valor de una Cápsula. El archivo de encabezado
correspondiente al módulo proporciona una macro que se encarga de importar el módulo y recuperar sus punteros C API;
los módulos de cliente solo tienen que llamar a esta macro antes de acceder a la API de C.
The exporting module is a modification of the spam module from section Un ejemplo simple. The function spam.
system() does not call the C library function system() directly, but a function PySpam_System(), which
would of course do something more complicated in reality (such as adding «spam» to every command). This function
PySpam_System() is also exported to other extension modules.
The function PySpam_System() is a plain C function, declared static like everything else:
static int
PySpam_System(const char *command)
{
return system(command);
}
El #define se usa para decirle al archivo de encabezado que se está incluyendo en el módulo de exportación, no en un
módulo de cliente. Finalmente, la función de inicialización del módulo debe encargarse de inicializar la matriz de punteros
de API C:
PyMODINIT_FUNC
PyInit_spam(void)
{
PyObject *m;
static void *PySpam_API[PySpam_API_pointers];
PyObject *c_api_object;
m = PyModule_Create(&spammodule);
if (m == NULL)
return NULL;
return m;
}
Note that PySpam_API is declared static; otherwise the pointer array would disappear when PyInit_spam()
terminates!
La mayor parte del trabajo está en el archivo de encabezado spammodule.h, que se ve así:
#ifndef Py_SPAMMODULE_H
#define Py_SPAMMODULE_H
#ifdef __cplusplus
extern "C" {
#endif
/* C API functions */
#define PySpam_System_NUM 0
#define PySpam_System_RETURN int
#define PySpam_System_PROTO (const char *command)
#ifdef SPAM_MODULE
/* This section is used when compiling spammodule.c */
#else
/* This section is used in modules that use spammodule's API */
#define PySpam_System \
(*(PySpam_System_RETURN (*)PySpam_System_PROTO) PySpam_API[PySpam_System_NUM])
#endif
#ifdef __cplusplus
}
#endif
All that a client module must do in order to have access to the function PySpam_System() is to call the function (or
rather macro) import_spam() in its initialization function:
PyMODINIT_FUNC
PyInit_client(void)
{
PyObject *m;
m = PyModule_Create(&clientmodule);
if (m == NULL)
return NULL;
if (import_spam() < 0)
return NULL;
/* additional initialization can happen here */
return m;
}
La principal desventaja de este enfoque es que el archivo spammodule.h es bastante complicado. Sin embargo, la
estructura básica es la misma para cada función que se exporta, por lo que solo se debe aprender una vez.
Finalmente, debe mencionarse que las cápsulas ofrecen una funcionalidad adicional, que es especialmente útil para la
asignación de memoria y la desasignación del puntero almacenado en una cápsula. Los detalles se describen en el Ma-
nual de referencia de Python/C API en la sección capsules y en la implementación de Capsules (archivos Include/
pycapsule.h y Objects/pycapsule.c en la distribución del código fuente de Python).
Python le permite al escritor de un módulo de extensión C definir nuevos tipos que pueden ser manipulados desde el
código Python, al igual que los tipos incorporados str y list. El código para todos los tipos de extensión sigue un
patrón, pero hay algunos detalles que debe comprender antes de comenzar. Este documento es una introducción suave al
tema.
2.2.1 Lo básico
The CPython runtime sees all Python objects as variables of type PyObject*, which serves as a «base type» for all
Python objects. The PyObject structure itself only contains the object’s reference count and a pointer to the object’s
«type object». This is where the action is; the type object determines which (C) functions get called by the interpreter
when, for instance, an attribute gets looked up on an object, a method called, or it is multiplied by another object. These
C functions are called «type methods».
Por lo tanto, si desea definir un nuevo tipo de extensión, debe crear un nuevo objeto de tipo.
This sort of thing can only be explained by example, so here’s a minimal, but complete, module that defines a new type
named Custom inside a C extension module custom:
Nota: Lo que estamos mostrando aquí es la forma tradicional de definir tipos de extensión estáticos. Debe ser adecuado
para la mayoría de los usos. La API de C también permite definir tipos de extensiones asignadas en el montón utilizando
la función PyType_FromSpec(), que no se trata en este tutorial.
#define PY_SSIZE_T_CLEAN
#include <Python.h>
typedef struct {
PyObject_HEAD
/* Type-specific fields go here. */
} CustomObject;
PyMODINIT_FUNC
PyInit_custom(void)
{
PyObject *m;
if (PyType_Ready(&CustomType) < 0)
return NULL;
m = PyModule_Create(&custommodule);
if (m == NULL)
return NULL;
Py_INCREF(&CustomType);
if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType) < 0) {
Py_DECREF(&CustomType);
Py_DECREF(m);
return NULL;
}
return m;
}
Ahora, eso es bastante para asimilar a la vez, pero espero que los fragmentos le resulten familiares del capítulo anterior.
Este archivo define tres cosas:
1. What a Custom object contains: this is the CustomObject struct, which is allocated once for each Custom
instance.
2. How the Custom type behaves: this is the CustomType struct, which defines a set of flags and function pointers
that the interpreter inspects when specific operations are requested.
3. How to initialize the custom module: this is the PyInit_custom function and the associated custommodule
struct.
La primera parte es:
typedef struct {
PyObject_HEAD
} CustomObject;
This is what a Custom object will contain. PyObject_HEAD is mandatory at the start of each object struct and defines
a field called ob_base of type PyObject, containing a pointer to a type object and a reference count (these can be
accessed using the macros Py_TYPE and Py_REFCNT respectively). The reason for the macro is to abstract away the
layout and to enable additional fields in debug builds.
Nota: No hay punto y coma (;) arriba después de la macro PyObject_HEAD. Tenga cuidado de agregar uno por
accidente: algunos compiladores se quejarán.
Por supuesto, los objetos generalmente almacenan datos adicionales además del estándar PyObject_HEAD repetitivo;
por ejemplo, aquí está la definición de puntos flotantes del estándar de Python:
typedef struct {
PyObject_HEAD
double ob_fval;
} PyFloatObject;
Nota: Recomendamos utilizar los inicializadores designados al estilo C99 como se indica arriba, para evitar enumerar
todos los campos PyTypeObject que no le interesan y también para evitar preocuparse por el orden de declaración de
los campos.
La definición real de PyTypeObject en object.h tiene muchos más campos que la definición anterior. El compilador
de C rellenará los campos restantes con ceros, y es una práctica común no especificarlos explícitamente a menos que los
necesite.
Lo vamos a separar, un campo a la vez:
.ob_base = PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "custom.Custom",
El nombre de nuestro tipo. Esto aparecerá en la representación textual predeterminada de nuestros objetos y en algunos
mensajes de error, por ejemplo:
Note that the name is a dotted name that includes both the module name and the name of the type within the module.
The module in this case is custom and the type is Custom, so we set the type name to custom.Custom. Using the
real dotted import path is important to make your type compatible with the pydoc and pickle modules.
.tp_basicsize = sizeof(CustomObject),
.tp_itemsize = 0,
This is so that Python knows how much memory to allocate when creating new Custom instances. tp_itemsize is
only used for variable-sized objects and should otherwise be zero.
Nota: If you want your type to be subclassable from Python, and your type has the same tp_basicsize as its base
type, you may have problems with multiple inheritance. A Python subclass of your type will have to list your type first
in its __bases__, or else it will not be able to call your type’s __new__() method without getting an error. You can
avoid this problem by ensuring that your type has a larger value for tp_basicsize than its base type does. Most of the
time, this will be true anyway, because either your base type will be object, or else you will be adding data members
to your base type, and therefore increasing its size.
.tp_flags = Py_TPFLAGS_DEFAULT,
Todos los tipos deben incluir esta constante en sus banderas. Habilita todos los miembros definidos hasta al menos Python
3.3. Si necesita más miembros, necesitará O (OR) las banderas correspondientes.
Proporcionamos una cadena de documentos para el tipo en tp_doc.
To enable object creation, we have to provide a tp_new handler. This is the equivalent of the Python method
__new__(), but has to be specified explicitly. In this case, we can just use the default implementation provided by
the API function PyType_GenericNew().
.tp_new = PyType_GenericNew,
Everything else in the file should be familiar, except for some code in PyInit_custom():
if (PyType_Ready(&CustomType) < 0)
return;
This initializes the Custom type, filling in a number of members to the appropriate default values, including ob_type
that we initially set to NULL.
Py_INCREF(&CustomType);
if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType) < 0) {
Py_DECREF(&CustomType);
Py_DECREF(m);
return NULL;
}
This adds the type to the module dictionary. This allows us to create Custom instances by calling the Custom class:
That’s it! All that remains is to build it; put the above code in a file called custom.c,
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[project]
name = "custom"
version = "1"
in a shell should produce a file custom.so in a subdirectory and install it; now fire up Python — you should be able to
import custom and play around with Custom objects.
Eso no fue tan difícil, ¿verdad?
Por supuesto, el tipo personalizado actual es bastante poco interesante. No tiene datos y no hace nada. Ni siquiera se
puede subclasificar.
Let’s extend the basic example to add some data and methods. Let’s also make the type usable as a base class. We’ll create
a new module, custom2 that adds these capabilities:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <stddef.h> /* for offsetof() */
typedef struct {
PyObject_HEAD
PyObject *first; /* first name */
PyObject *last; /* last name */
int number;
} CustomObject;
static void
Custom_dealloc(CustomObject *self)
{
Py_XDECREF(self->first);
Py_XDECREF(self->last);
Py_TYPE(self)->tp_free((PyObject *) self);
}
static PyObject *
Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
(continué en la próxima página)
static int
Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL;
if (first) {
Py_XSETREF(self->first, Py_NewRef(first));
}
if (last) {
Py_XSETREF(self->last, Py_NewRef(last));
}
return 0;
}
static PyObject *
Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored))
{
if (self->first == NULL) {
PyErr_SetString(PyExc_AttributeError, "first");
return NULL;
}
if (self->last == NULL) {
(continué en la próxima página)
PyMODINIT_FUNC
PyInit_custom2(void)
{
PyObject *m;
if (PyType_Ready(&CustomType) < 0)
return NULL;
m = PyModule_Create(&custommodule);
if (m == NULL)
return NULL;
return m;
}
typedef struct {
PyObject_HEAD
PyObject *first; /* first name */
PyObject *last; /* last name */
int number;
} CustomObject;
Debido a que ahora tenemos datos para administrar, debemos ser más cuidadosos con la asignación de objetos y la
desasignación. Como mínimo, necesitamos un método de desasignación:
static void
Custom_dealloc(CustomObject *self)
{
Py_XDECREF(self->first);
Py_XDECREF(self->last);
Py_TYPE(self)->tp_free((PyObject *) self);
}
This method first clears the reference counts of the two Python attributes. Py_XDECREF() correctly handles the case
where its argument is NULL (which might happen here if tp_new failed midway). It then calls the tp_free member
of the object’s type (computed by Py_TYPE(self)) to free the object’s memory. Note that the object’s type might not
be CustomType, because the object may be an instance of a subclass.
Nota: La conversión explícita a destructor anterior es necesaria porque definimos Custom_dealloc para tomar
un argumento CustomObject *, pero el puntero de función tp_dealloc espera recibir un argumento PyObject
*. De lo contrario, el compilador emitirá una advertencia. Este es un polimorfismo orientado a objetos, en C!
Queremos asegurarnos de que el nombre y el apellido se inicialicen en cadenas de caracteres vacías, por lo que propor-
cionamos una implementación tp_new:
static PyObject *
Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
CustomObject *self;
self = (CustomObject *) type->tp_alloc(type, 0);
if (self != NULL) {
self->first = PyUnicode_FromString("");
if (self->first == NULL) {
Py_DECREF(self);
return NULL;
}
self->last = PyUnicode_FromString("");
if (self->last == NULL) {
Py_DECREF(self);
return NULL;
}
self->number = 0;
}
return (PyObject *) self;
}
.tp_new = Custom_new,
The tp_new handler is responsible for creating (as opposed to initializing) objects of the type. It is exposed in Python
as the __new__() method. It is not required to define a tp_new member, and indeed many extension types will
simply reuse PyType_GenericNew() as done in the first version of the Custom type above. In this case, we use the
tp_new handler to initialize the first and last attributes to non-NULL default values.
tp_new se pasa el tipo que se instancia (no necesariamente CustomType, si se instancia una subclase) y cualquier
argumento pasado cuando se llamó al tipo, y se espera que retorna la instancia creada. Los manejadores tp_new siem-
pre aceptan argumentos posicionales y de palabras clave, pero a menudo ignoran los argumentos, dejando el manejo de
argumentos al inicializador (también conocido como, tp_init en C o __init__ en Python).
Nota: tp_new no debería llamar explícitamente a tp_init, ya que el intérprete lo hará por sí mismo.
Como la asignación de memoria puede fallar, debemos verificar el resultado tp_alloc contra NULL antes de continuar.
Nota: No llenamos la ranura tp_alloc nosotros mismos. Más bien PyType_Ready() lo llena para nosotros al
heredarlo de nuestra clase base, que es object por defecto. La mayoría de los tipos utilizan la estrategia de asignación
predeterminada.
Nota: If you are creating a co-operative tp_new (one that calls a base type’s tp_new or __new__()), you must not
try to determine what method to call using method resolution order at runtime. Always statically determine what type
you are going to call, and call its tp_new directly, or via type->tp_base->tp_new. If you do not do this, Python
subclasses of your type that also inherit from other Python-defined classes may not work correctly. (Specifically, you may
not be able to create instances of such subclasses without getting a TypeError.)
También definimos una función de inicialización que acepta argumentos para proporcionar valores iniciales para nuestra
instancia:
static int
Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL, *tmp;
if (first) {
tmp = self->first;
Py_INCREF(first);
self->first = first;
Py_XDECREF(tmp);
}
(continué en la próxima página)
The tp_init slot is exposed in Python as the __init__() method. It is used to initialize an object after it’s created.
Initializers always accept positional and keyword arguments, and they should return either 0 on success or -1 on error.
Unlike the tp_new handler, there is no guarantee that tp_init is called at all (for example, the pickle module
by default doesn’t call __init__() on unpickled instances). It can also be called multiple times. Anyone can call the
__init__() method on our objects. For this reason, we have to be extra careful when assigning the new attribute
values. We might be tempted, for example to assign the first member like this:
if (first) {
Py_XDECREF(self->first);
Py_INCREF(first);
self->first = first;
}
Pero esto sería arriesgado. Nuestro tipo no restringe el tipo del primer miembro, por lo que podría ser cualquier tipo
de objeto. Podría tener un destructor que haga que se ejecute código que intente acceder al primer miembro; o ese
destructor podría liberar el Global Interpreter Lock y permite que se ejecute código arbitrario en otros hilos que acceden
y modifican nuestro objeto.
Para ser paranoicos y protegernos de esta posibilidad, casi siempre reasignamos miembros antes de disminuir sus recuentos
de referencias. ¿Cuándo no tenemos que hacer esto?
• cuando sabemos absolutamente que el recuento de referencia es mayor que 1;
• cuando sabemos que la desasignación del objeto1 no liberará el GIL ni causará ninguna llamada al código de nuestro
tipo;
• al disminuir un recuento de referencias en un manejador tp_dealloc en un tipo que no admite la recolección
de basura cíclica2 .
Queremos exponer nuestras variables de instancia como atributos. Hay varias formas de hacerlo. La forma más simple es
definir definiciones de miembros:
1 Esto es cierto cuando sabemos que el objeto es un tipo básico, como una cadena o un flotador.
2 Nos basamos en esto en el manejador tp_dealloc en este ejemplo, porque nuestro tipo no admite la recolección de basura.
.tp_members = Custom_members,
Cada definición de miembro tiene un nombre de miembro, tipo, desplazamiento, banderas de acceso y cadena de caracteres
de documentación. Consulte la sección Gestión de atributos genéricos a continuación para obtener más detalles.
Una desventaja de este enfoque es que no proporciona una forma de restringir los tipos de objetos que se pueden asignar
a los atributos de Python. Esperamos que el nombre y el apellido sean cadenas, pero se pueden asignar objetos de Python.
Además, los atributos se pueden eliminar, configurando los punteros C en NULL. Si bien podemos asegurarnos de que
los miembros se inicialicen en valores que no sean NULL, los miembros se pueden establecer en NULL si se eliminan los
atributos.
We define a single method, Custom.name(), that outputs the objects name as the concatenation of the first and last
names.
static PyObject *
Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored))
{
if (self->first == NULL) {
PyErr_SetString(PyExc_AttributeError, "first");
return NULL;
}
if (self->last == NULL) {
PyErr_SetString(PyExc_AttributeError, "last");
return NULL;
}
return PyUnicode_FromFormat("%S %S", self->first, self->last);
}
The method is implemented as a C function that takes a Custom (or Custom subclass) instance as the first argument.
Methods always take an instance as the first argument. Methods often take positional and keyword arguments as well, but
in this case we don’t take any and don’t need to accept a positional argument tuple or keyword argument dictionary. This
method is equivalent to the Python method:
def name(self):
return "%s %s" % (self.first, self.last)
Note that we have to check for the possibility that our first and last members are NULL. This is because they can
be deleted, in which case they are set to NULL. It would be better to prevent deletion of these attributes and to restrict the
attribute values to be strings. We’ll see how to do that in the next section.
Ahora que hemos definido el método, necesitamos crear un arreglo de definiciones de métodos:
(note that we used the METH_NOARGS flag to indicate that the method is expecting no arguments other than self)
y asignarlo a la ranura tp_methods:
.tp_methods = Custom_methods,
Finally, we’ll make our type usable as a base class for subclassing. We’ve written our methods carefully so far so that
they don’t make any assumptions about the type of the object being created or used, so all we need to do is to add the
We rename PyInit_custom() to PyInit_custom2(), update the module name in the PyModuleDef struct,
and update the full class name in the PyTypeObject struct.
Finally, we update our setup.py file to include the new module,
In this section, we’ll provide finer control over how the first and last attributes are set in the Custom example. In
the previous version of our module, the instance variables first and last could be set to non-string values or even
deleted. We want to make sure that these attributes always contain strings.
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <stddef.h> /* for offsetof() */
typedef struct {
PyObject_HEAD
PyObject *first; /* first name */
PyObject *last; /* last name */
int number;
} CustomObject;
static void
Custom_dealloc(CustomObject *self)
{
Py_XDECREF(self->first);
Py_XDECREF(self->last);
Py_TYPE(self)->tp_free((PyObject *) self);
}
static PyObject *
Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
CustomObject *self;
self = (CustomObject *) type->tp_alloc(type, 0);
if (self != NULL) {
self->first = PyUnicode_FromString("");
if (self->first == NULL) {
Py_DECREF(self);
return NULL;
}
self->last = PyUnicode_FromString("");
(continué en la próxima página)
static int
Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL;
if (first) {
Py_SETREF(self->first, Py_NewRef(first));
}
if (last) {
Py_SETREF(self->last, Py_NewRef(last));
}
return 0;
}
static PyObject *
Custom_getfirst(CustomObject *self, void *closure)
{
return Py_NewRef(self->first);
}
static int
Custom_setfirst(CustomObject *self, PyObject *value, void *closure)
{
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
return -1;
}
if (!PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError,
"The first attribute value must be a string");
return -1;
}
Py_SETREF(self->first, Py_NewRef(value));
return 0;
}
static int
Custom_setlast(CustomObject *self, PyObject *value, void *closure)
{
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute");
return -1;
}
if (!PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError,
"The last attribute value must be a string");
return -1;
}
Py_SETREF(self->last, Py_NewRef(value));
return 0;
}
static PyObject *
Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored))
{
return PyUnicode_FromFormat("%S %S", self->first, self->last);
}
PyMODINIT_FUNC
PyInit_custom3(void)
{
PyObject *m;
if (PyType_Ready(&CustomType) < 0)
return NULL;
m = PyModule_Create(&custommodule);
if (m == NULL)
return NULL;
return m;
}
To provide greater control, over the first and last attributes, we’ll use custom getter and setter functions. Here are
the functions for getting and setting the first attribute:
static PyObject *
Custom_getfirst(CustomObject *self, void *closure)
{
Py_INCREF(self->first);
return self->first;
}
static int
Custom_setfirst(CustomObject *self, PyObject *value, void *closure)
{
PyObject *tmp;
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
return -1;
}
if (!PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError,
"The first attribute value must be a string");
return -1;
}
tmp = self->first;
Py_INCREF(value);
self->first = value;
Py_DECREF(tmp);
return 0;
}
The getter function is passed a Custom object and a «closure», which is a void pointer. In this case, the closure is
ignored. (The closure supports an advanced usage in which definition data is passed to the getter and setter. This could,
for example, be used to allow a single set of getter and setter functions that decide the attribute to get or set based on data
in the closure.)
The setter function is passed the Custom object, the new value, and the closure. The new value may be NULL, in which
case the attribute is being deleted. In our setter, we raise an error if the attribute is deleted or if its new value is not a
string.
Creamos un arreglo de estructuras PyGetSetDef:
.tp_getset = Custom_getsetters,
El último elemento en la estructura PyGetSetDef es el «cierre» (closure) mencionado anteriormente. En este caso, no
estamos usando un cierre, por lo que simplemente pasamos NULL.
También eliminamos las definiciones de miembro para estos atributos:
También necesitamos actualizar el manejador tp_init para permitir que solo se pasen las cadenas3 :
static int
Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL, *tmp;
if (first) {
tmp = self->first;
Py_INCREF(first);
self->first = first;
Py_DECREF(tmp);
}
if (last) {
(continué en la próxima página)
3 Ahora sabemos que el primer y el último miembro son cadenas de caracteres, por lo que quizás podríamos ser menos cuidadosos al disminuir sus
recuentos de referencia, sin embargo, aceptamos instancias de subclases de cadenas. A pesar de que la desasignación de cadenas normales no volverá
a llamar a nuestros objetos, no podemos garantizar que la desasignación de una instancia de una subclase de cadena de caracteres no vuelva a llamar a
nuestros objetos.
Con estos cambios, podemos asegurar que los miembros primero y último nunca sean NULL, por lo que podemos
eliminar las comprobaciones de los valores NULL en casi todos los casos. Esto significa que la mayoría de las llamadas
Py_XDECREF() se pueden convertir en llamadas Py_DECREF(). El único lugar donde no podemos cambiar estas
llamadas es en la implementación tp_dealloc, donde existe la posibilidad de que la inicialización de estos miembros
falle en tp_new.
También cambiamos el nombre de la función de inicialización del módulo y el nombre del módulo en la función de
inicialización, como lo hicimos antes, y agregamos una definición adicional al archivo setup.py.
Python tiene un recolector de basura cíclico (GC) que puede identificar objetos innecesarios incluso cuando sus recuentos
de referencia no son cero. Esto puede suceder cuando los objetos están involucrados en ciclos. Por ejemplo, considere:
>>> l = []
>>> l.append(l)
>>> del l
En este ejemplo, creamos una lista que se contiene a sí misma. Cuando lo eliminamos, todavía tiene una referencia de sí
mismo. Su recuento de referencia no cae a cero. Afortunadamente, el recolector cíclico de basura de Python finalmente
descubrirá que la lista es basura y la liberará.
In the second version of the Custom example, we allowed any kind of object to be stored in the first or last
attributes4 . Besides, in the second and third versions, we allowed subclassing Custom, and subclasses may add arbitrary
attributes. For any of those two reasons, Custom objects can participate in cycles:
To allow a Custom instance participating in a reference cycle to be properly detected and collected by the cyclic GC,
our Custom type needs to fill two additional slots and to enable a flag that enables these slots:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <stddef.h> /* for offsetof() */
typedef struct {
PyObject_HEAD
PyObject *first; /* first name */
PyObject *last; /* last name */
int number;
(continué en la próxima página)
4 Además, incluso con nuestros atributos restringidos a instancias de cadenas, el usuario podría pasar subclases arbitrarias str y, por lo tanto, seguir
static int
Custom_traverse(CustomObject *self, visitproc visit, void *arg)
{
Py_VISIT(self->first);
Py_VISIT(self->last);
return 0;
}
static int
Custom_clear(CustomObject *self)
{
Py_CLEAR(self->first);
Py_CLEAR(self->last);
return 0;
}
static void
Custom_dealloc(CustomObject *self)
{
PyObject_GC_UnTrack(self);
Custom_clear(self);
Py_TYPE(self)->tp_free((PyObject *) self);
}
static PyObject *
Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
CustomObject *self;
self = (CustomObject *) type->tp_alloc(type, 0);
if (self != NULL) {
self->first = PyUnicode_FromString("");
if (self->first == NULL) {
Py_DECREF(self);
return NULL;
}
self->last = PyUnicode_FromString("");
if (self->last == NULL) {
Py_DECREF(self);
return NULL;
}
self->number = 0;
}
return (PyObject *) self;
}
static int
Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL;
if (first) {
Py_SETREF(self->first, Py_NewRef(first));
}
if (last) {
Py_SETREF(self->last, Py_NewRef(last));
}
return 0;
}
static PyObject *
Custom_getfirst(CustomObject *self, void *closure)
{
return Py_NewRef(self->first);
}
static int
Custom_setfirst(CustomObject *self, PyObject *value, void *closure)
{
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
return -1;
}
if (!PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError,
"The first attribute value must be a string");
return -1;
}
Py_XSETREF(self->first, Py_NewRef(value));
return 0;
}
static PyObject *
Custom_getlast(CustomObject *self, void *closure)
{
return Py_NewRef(self->last);
}
static int
Custom_setlast(CustomObject *self, PyObject *value, void *closure)
{
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute");
return -1;
}
if (!PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError,
"The last attribute value must be a string");
return -1;
}
Py_XSETREF(self->last, Py_NewRef(value));
(continué en la próxima página)
static PyObject *
Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored))
{
return PyUnicode_FromFormat("%S %S", self->first, self->last);
}
PyMODINIT_FUNC
PyInit_custom4(void)
{
PyObject *m;
if (PyType_Ready(&CustomType) < 0)
return NULL;
m = PyModule_Create(&custommodule);
if (m == NULL)
(continué en la próxima página)
return m;
}
Primero, el método transversal permite que el GC cíclico conozca los subobjetos que podrían participar en los ciclos:
static int
Custom_traverse(CustomObject *self, visitproc visit, void *arg)
{
int vret;
if (self->first) {
vret = visit(self->first, arg);
if (vret != 0)
return vret;
}
if (self->last) {
vret = visit(self->last, arg);
if (vret != 0)
return vret;
}
return 0;
}
For each subobject that can participate in cycles, we need to call the visit() function, which is passed to the traversal
method. The visit() function takes as arguments the subobject and the extra argument arg passed to the traversal
method. It returns an integer value that must be returned if it is non-zero.
Python proporciona una macro Py_VISIT() que automatiza las funciones de visita de llamada. Con Py_VISIT(),
podemos minimizar la cantidad de repeticiones en Custom_traverse:
static int
Custom_traverse(CustomObject *self, visitproc visit, void *arg)
{
Py_VISIT(self->first);
Py_VISIT(self->last);
return 0;
}
Nota: La implementación tp_traverse debe nombrar sus argumentos exactamente visit y arg para usar
Py_VISIT().
En segundo lugar, debemos proporcionar un método para borrar cualquier subobjeto que pueda participar en los ciclos:
static int
Custom_clear(CustomObject *self)
{
Py_CLEAR(self->first);
Py_CLEAR(self->last);
(continué en la próxima página)
Observe el uso de la macro Py_CLEAR(). Es la forma recomendada y segura de borrar los atributos de datos de tipos
arbitrarios al tiempo que disminuye sus recuentos de referencia. Si tuviera que llamar a Py_XDECREF() en lugar del
atributo antes de establecerlo en NULL, existe la posibilidad de que el destructor del atributo vuelva a llamar al código
que lee el atributo nuevamente (especialmente si hay un ciclo de referencia).
Sin embargo, es mucho más fácil y menos propenso a errores usar siempre Py_CLEAR() al eliminar un atributo. ¡No
intentes micro-optimizar a expensas de la robustez!
El desasignador Custom_dealloc puede llamar a un código arbitrario al borrar los atributos. Significa que el GC
circular se puede activar dentro de la función. Dado que el GC asume que el recuento de referencias no es cero, debemos
destrabar el objeto del GC llamando a PyObject_GC_UnTrack() antes de borrar los miembros. Aquí está nuestro
reubicador reimplementado usando PyObject_GC_UnTrack() y Custom_clear:
static void
Custom_dealloc(CustomObject *self)
{
PyObject_GC_UnTrack(self);
Custom_clear(self);
Py_TYPE(self)->tp_free((PyObject *) self);
}
Eso es prácticamente todo. Si hubiéramos escrito controladores personalizados tp_alloc o tp_free, tendríamos
que modificarlos para la recolección de basura cíclica. La mayoría de las extensiones usarán las versiones proporcionadas
automáticamente.
Es posible crear nuevos tipos de extensión que se derivan de los tipos existentes. Es más fácil heredar de los tipos incor-
porados, ya que una extensión puede usar fácilmente PyTypeObject que necesita. Puede ser difícil compartir estas
estructuras PyTypeObject entre módulos de extensión.
In this example we will create a SubList type that inherits from the built-in list type. The new type will be completely
compatible with regular lists, but will have an additional increment() method that increases an internal counter:
>>> import sublist
>>> s = sublist.SubList(range(3))
>>> s.extend(s)
>>> print(len(s))
6
(continué en la próxima página)
#define PY_SSIZE_T_CLEAN
#include <Python.h>
typedef struct {
PyListObject list;
int state;
} SubListObject;
static PyObject *
SubList_increment(SubListObject *self, PyObject *unused)
{
self->state++;
return PyLong_FromLong(self->state);
}
static int
SubList_init(SubListObject *self, PyObject *args, PyObject *kwds)
{
if (PyList_Type.tp_init((PyObject *) self, args, kwds) < 0)
return -1;
self->state = 0;
return 0;
}
PyMODINIT_FUNC
PyInit_sublist(void)
{
(continué en la próxima página)
m = PyModule_Create(&sublistmodule);
if (m == NULL)
return NULL;
Py_INCREF(&SubListType);
if (PyModule_AddObject(m, "SubList", (PyObject *) &SubListType) < 0) {
Py_DECREF(&SubListType);
Py_DECREF(m);
return NULL;
}
return m;
}
As you can see, the source code closely resembles the Custom examples in previous sections. We will break down the
main differences between them.
typedef struct {
PyListObject list;
int state;
} SubListObject;
La diferencia principal para los objetos de tipo derivado es que la estructura de objeto del tipo base debe ser el primer
valor. El tipo base ya incluirá PyObject_HEAD() al comienzo de su estructura.
When a Python object is a SubList instance, its PyObject * pointer can be safely cast to both PyListObject
* and SubListObject *:
static int
SubList_init(SubListObject *self, PyObject *args, PyObject *kwds)
{
if (PyList_Type.tp_init((PyObject *) self, args, kwds) < 0)
return -1;
self->state = 0;
return 0;
}
We see above how to call through to the __init__() method of the base type.
Este patrón es importante cuando se escribe un tipo con miembros personalizados tp_new y tp_dealloc. El mane-
jador tp_new no debería crear realmente la memoria para el objeto con su tp_alloc, pero deja que la clase base lo
maneje llamando a su propio tp_new.
La estructura PyTypeObject admite a tp_base especificando la clase base concreta del tipo. Debido a problemas
de compilación multiplataforma, no puede llenar ese campo directamente con una referencia a PyList_Type; debe
hacerse más tarde en la función de inicialización del módulo:
PyMODINIT_FUNC
PyInit_sublist(void)
{
PyObject* m;
SubListType.tp_base = &PyList_Type;
(continué en la próxima página)
m = PyModule_Create(&sublistmodule);
if (m == NULL)
return NULL;
Py_INCREF(&SubListType);
if (PyModule_AddObject(m, "SubList", (PyObject *) &SubListType) < 0) {
Py_DECREF(&SubListType);
Py_DECREF(m);
return NULL;
}
return m;
}
Antes de llamar a PyType_Ready(), la estructura de tipo debe tener el espacio tp_base rellenado. Cuando deriva-
mos un tipo existente, no es necesario completar el tp_alloc ranura con PyType_GenericNew() – la función de
asignación del tipo base será heredada.
After that, calling PyType_Ready() and adding the type object to the module is the same as with the basic Custom
examples.
Notas al pie
Esta sección tiene como objetivo dar un vistazo rápido a los diversos métodos de tipo que puede implementar y lo que
hacen.
Aquí está la definición de PyTypeObject, con algunos campos que solo se usan en las versiones de depuración omitidas:
destructor tp_dealloc;
Py_ssize_t tp_vectorcall_offset;
getattrfunc tp_getattr;
setattrfunc tp_setattr;
PyAsyncMethods *tp_as_async; /* formerly known as tp_compare (Python 2)
or tp_reserved (Python 3) */
reprfunc tp_repr;
PyNumberMethods *tp_as_number;
PySequenceMethods *tp_as_sequence;
PyMappingMethods *tp_as_mapping;
hashfunc tp_hash;
ternaryfunc tp_call;
reprfunc tp_str;
getattrofunc tp_getattro;
setattrofunc tp_setattro;
/* Iterators */
getiterfunc tp_iter;
iternextfunc tp_iternext;
destructor tp_finalize;
vectorcallfunc tp_vectorcall;
Esos son muchos métodos. Sin embargo, no se preocupe demasiado: si tiene un tipo que desea definir, es muy probable
que solo implemente un puñado de estos.
Como probablemente espera ahora, vamos a repasar esto y daremos más información sobre los diversos controladores.
No iremos en el orden en que se definen en la estructura, porque hay mucho equipaje histórico que afecta el orden de los
campos. A menudo es más fácil encontrar un ejemplo que incluya los campos que necesita y luego cambiar los valores
para adaptarlos a su nuevo tipo.
El nombre del tipo – como se mencionó en el capítulo anterior, aparecerá en varios lugares, casi por completo para fines
de diagnóstico. ¡Intente elegir algo que sea útil en tal situación!
Estos campos le dicen al tiempo de ejecución cuánta memoria asignar cuando se crean nuevos objetos de este tipo. Python
tiene algún soporte incorporado para estructuras de longitud variable (piense: cadenas, tuplas) que es donde entra el campo
tp_itemsize. Esto se tratará más adelante.
Aquí puede poner una cadena de caracteres (o su dirección) que desea que se retorne cuando el script de Python haga
referencia a obj.__doc__ para recuperar el docstring.
Ahora llegamos a los métodos de tipo básicos: los que implementarán la mayoría de los tipos de extensión.
destructor tp_dealloc;
Se llama a esta función cuando el recuento de referencia de la instancia de su tipo se reduce a cero y el intérprete de Python
quiere reclamarlo. Si su tipo tiene memoria para liberar u otra limpieza para realizar, puede ponerla aquí. El objeto en sí
mismo necesita ser liberado aquí también. Aquí hay un ejemplo de esta función:
static void
newdatatype_dealloc(newdatatypeobject *obj)
{
free(obj->obj_UnderlyingDatatypePtr);
Py_TYPE(obj)->tp_free((PyObject *)obj);
}
Si su tipo admite la recolección de basura, el destructor debe llamar a PyObject_GC_UnTrack() antes de borrar
cualquier campo miembro:
static void
newdatatype_dealloc(newdatatypeobject *obj)
{
PyObject_GC_UnTrack(obj);
Py_CLEAR(obj->other_obj);
...
Py_TYPE(obj)->tp_free((PyObject *)obj);
}
Un requisito importante de la función desasignador es que deja solo las excepciones pendientes. Esto es importante ya que
los desasignadores se llaman con frecuencia cuando el intérprete desenrolla la pila de Python; cuando la pila se desenrolla
debido a una excepción (en lugar de retornos normales), no se hace nada para proteger a los desasignadores de memoria
(deallocator) de ver que ya se ha establecido una excepción. Cualquier acción que realice un desasignador que pueda hacer
que se ejecute código Python adicional puede detectar que se ha establecido una excepción. Esto puede conducir a errores
engañosos del intérprete. La forma correcta de protegerse contra esto es guardar una excepción pendiente antes de realizar
la acción insegura y restaurarla cuando haya terminado. Esto se puede hacer usando las funciones PyErr_Fetch() y
PyErr_Restore():
static void
my_dealloc(PyObject *obj)
{
MyObject *self = (MyObject *) obj;
PyObject *cbresult;
if (self->my_callback != NULL) {
PyObject *err_type, *err_value, *err_traceback;
cbresult = PyObject_CallNoArgs(self->my_callback);
if (cbresult == NULL)
PyErr_WriteUnraisable(self->my_callback);
else
Py_DECREF(cbresult);
Py_DECREF(self->my_callback);
}
Py_TYPE(obj)->tp_free((PyObject*)self);
}
Nota: Existen limitaciones para lo que puede hacer de manera segura en una función de desasignación. Primero, si su
tipo admite la recolección de basura (usando tp_traverse o tp_clear), algunos de los miembros del objeto pueden
haber sido borrados o finalizados por el time tp_dealloc es llamado. Segundo, en tp_dealloc, su objeto está en
un estado inestable: su recuento de referencia es igual a cero. Cualquier llamada a un objeto o API no trivial (como en el
ejemplo anterior) podría terminar llamando tp_dealloc nuevamente, causando una doble liberación y un bloqueo.
Comenzando con Python 3.4, se recomienda no poner ningún código de finalización complejo en tp_dealloc, y en su
lugar use el nuevo método de tipo tp_finalize.
Ver también:
PEP 442 explica el nuevo esquema de finalización.
En Python, hay dos formas de generar una representación textual de un objeto: la función repr(), y la función str().
(La función print() solo llama a str().) Estos controladores son opcionales.
reprfunc tp_repr;
reprfunc tp_str;
El manejador tp_repr debe retornar un objeto de cadena que contenga una representación de la instancia para la que
se llama. Aquí hay un ejemplo simple:
static PyObject *
newdatatype_repr(newdatatypeobject *obj)
{
return PyUnicode_FromFormat("Repr-ified_newdatatype{{size:%d}}",
obj->obj_UnderlyingDatatypePtr->size);
}
Si no se especifica un controlador tp_repr, el intérprete proporcionará una representación que utiliza el tp_name del
tipo y un valor de identificación exclusivo para el objeto.
El manejador tp_str es para str() lo que el manejador tp_repr descrito arriba es para repr(); es decir, se
llama cuando el código Python llama str() en una instancia de su objeto. Su implementación es muy similar a la
función tp_repr, pero la cadena resultante está destinada al consumo humano. Si tp_str no se especifica, en su lugar
se utiliza el controlador tp_repr.
Aquí hay un ejemplo simple:
static PyObject *
newdatatype_str(newdatatypeobject *obj)
{
return PyUnicode_FromFormat("Stringified_newdatatype{{size:%d}}",
obj->obj_UnderlyingDatatypePtr->size);
}
Para cada objeto que puede soportar atributos, el tipo correspondiente debe proporcionar las funciones que controlan
cómo se resuelven los atributos. Es necesario que haya una función que pueda recuperar atributos (si hay alguna definida),
y otra para establecer atributos (si se permite establecer atributos). La eliminación de un atributo es un caso especial, para
el cual el nuevo valor pasado al controlador es NULL.
Python admite dos pares de controladores de atributos; un tipo que admite atributos solo necesita implementar las fun-
ciones para un par. La diferencia es que un par toma el nombre del atributo como char*, mientras que el otro acepta
un PyObject*. Cada tipo puede usar cualquier par que tenga más sentido para la conveniencia de la implementación.
getattrfunc tp_getattr; /* char * version */
setattrfunc tp_setattr;
/* ... */
getattrofunc tp_getattro; /* PyObject * version */
setattrofunc tp_setattro;
Si acceder a los atributos de un objeto siempre es una operación simple (esto se explicará en breve), existen implemen-
taciones genéricas que se pueden usar para proporcionar la versión PyObject* de las funciones de administración de
atributos. La necesidad real de controladores de atributos específicos de tipo desapareció casi por completo a partir de
Python 2.2, aunque hay muchos ejemplos que no se han actualizado para usar algunos de los nuevos mecanismos genéricos
disponibles.
La mayoría de los tipos de extensión solo usan atributos simple. Entonces, ¿qué hace que los atributos sean simples? Solo
hay un par de condiciones que se deben cumplir:
1. El nombre de los atributos debe ser conocido cuando PyType_Ready() es llamado.
2. No se necesita un procesamiento especial para registrar que un atributo se buscó o se configuró, ni se deben tomar
acciones basadas en el valor.
Tenga en cuenta que esta lista no impone restricciones a los valores de los atributos, cuándo se calculan los valores o cómo
se almacenan los datos relevantes.
Cuando se llama a PyType_Ready(), utiliza tres tablas a las que hace referencia el objeto de tipo para crear descriptor
que se colocan en el diccionario del objeto de tipo. Cada descriptor controla el acceso a un atributo del objeto de instancia.
Cada una de las tablas es opcional; si los tres son NULL, las instancias del tipo solo tendrán atributos que se heredan de su
tipo base, y deberían dejar tp_getattro y los campos tp_setattro NULL también, permitiendo que el tipo base
maneje los atributos.
Las tablas se declaran como tres campos del tipo objeto:
Si tp_methods no es NULL, debe referirse a un arreglo de estructuras PyMethodDef. Cada entrada en la tabla es
una instancia de esta estructura:
One entry should be defined for each method provided by the type; no entries are needed for methods inherited from a
base type. One additional entry is needed at the end; it is a sentinel that marks the end of the array. The ml_name field
of the sentinel must be NULL.
La segunda tabla se utiliza para definir atributos que se asignan directamente a los datos almacenados en la instancia. Se
admite una variedad de tipos C primitivos, y el acceso puede ser de solo lectura o lectura-escritura. Las estructuras en la
tabla se definen como:
For each entry in the table, a descriptor will be constructed and added to the type which will be able to extract a value
from the instance structure. The type field should contain a type code like Py_T_INT or Py_T_DOUBLE; the value
will be used to determine how to convert Python values to and from C values. The flags field is used to store flags which
control how the attribute can be accessed: you can set it to Py_READONLY to prevent Python code from setting it.
Una ventaja interesante de usar la tabla tp_members para crear descriptores que se usan en tiempo de ejecución es
que cualquier atributo definido de esta manera puede tener un docstring asociada simplemente al proporcionar el texto en
la tabla. Una aplicación puede usar la API de introspección para recuperar el descriptor del objeto de clase y obtener el
docstring utilizando su atributo __doc__.
As with the tp_methods table, a sentinel entry with a ml_name value of NULL is required.
Para simplificar, solo la versión char* será demostrada aquí; el tipo del parámetro con nombre es la única diferencia
entre char* y PyObject* de la interfaz. Este ejemplo efectivamente hace lo mismo que el ejemplo genérico anterior,
pero no usa el soporte genérico agregado en Python 2.2. Explica cómo se llaman las funciones del controlador, de modo
que si necesita ampliar su funcionalidad, comprenderá lo que debe hacerse.
The tp_getattr handler is called when the object requires an attribute look-up. It is called in the same situations
where the __getattr__() method of a class would be called.
Aquí hay un ejemplo:
static PyObject *
newdatatype_getattr(newdatatypeobject *obj, char *name)
{
if (strcmp(name, "data") == 0)
{
return PyLong_FromLong(obj->data);
}
PyErr_Format(PyExc_AttributeError,
"'%.100s' object has no attribute '%.400s'",
Py_TYPE(obj)->tp_name, name);
return NULL;
}
The tp_setattr handler is called when the __setattr__() or __delattr__() method of a class instance
would be called. When an attribute should be deleted, the third parameter will be NULL. Here is an example that simply
raises an exception; if this were really all you wanted, the tp_setattr handler should be set to NULL.
static int
newdatatype_setattr(newdatatypeobject *obj, char *name, PyObject *v)
{
PyErr_Format(PyExc_RuntimeError, "Read-only attribute: %s", name);
return -1;
}
richcmpfunc tp_richcompare;
The tp_richcompare handler is called when comparisons are needed. It is analogous to the rich comparison methods,
like __lt__(), and also called by PyObject_RichCompare() and PyObject_RichCompareBool().
Esta función se llama con dos objetos de Python y el operador como argumentos, donde el operador es uno de Py_EQ,
Py_NE, Py_LE, Py_GE, Py_LT o Py_GT. Debe comparar los dos objetos con respecto al operador especificado y
retornar Py_True o Py_False si la comparación es exitosa, Py_NotImplemented para indicar que la comparación
no está implementada y se debe probar el método de comparación del otro objeto, o NULL si se estableció una excepción.
Aquí hay una implementación de muestra, para un tipo de datos que se considera igual si el tamaño de un puntero interno
es igual:
static PyObject *
newdatatype_richcmp(newdatatypeobject *obj1, newdatatypeobject *obj2, int op)
{
PyObject *result;
int c, size1, size2;
size1 = obj1->obj_UnderlyingDatatypePtr->size;
size2 = obj2->obj_UnderlyingDatatypePtr->size;
switch (op) {
case Py_LT: c = size1 < size2; break;
case Py_LE: c = size1 <= size2; break;
case Py_EQ: c = size1 == size2; break;
case Py_NE: c = size1 != size2; break;
case Py_GT: c = size1 > size2; break;
case Py_GE: c = size1 >= size2; break;
}
result = c ? Py_True : Py_False;
Py_INCREF(result);
return result;
}
Python admite una variedad de protocolos abstractos; las interfaces específicas proporcionadas para usar estas interfaces
están documentadas en abstract.
Varias de estas interfaces abstractas se definieron temprano en el desarrollo de la implementación de Python. En particular,
los protocolos de número, mapeo y secuencia han sido parte de Python desde el principio. Se han agregado otros protocolos
con el tiempo. Para los protocolos que dependen de varias rutinas de controlador de la implementación de tipo, los
protocolos más antiguos se han definido como bloques opcionales de controladores a los que hace referencia el objeto de
tipo. Para los protocolos más nuevos, hay espacios adicionales en el objeto de tipo principal, con un bit de marca que se
establece para indicar que los espacios están presentes y el intérprete debe verificarlos. (El bit de indicador no indica que
los valores de intervalo no son NULL. El indicador puede establecerse para indicar la presencia de un intervalo, pero un
intervalo aún puede estar vacío.):
PyNumberMethods *tp_as_number;
PySequenceMethods *tp_as_sequence;
PyMappingMethods *tp_as_mapping;
Si desea que su objeto pueda actuar como un número, una secuencia o un objeto de mapeo, entonces coloca la dirección de
una estructura que implementa el tipo C PyNumberMethods, PySequenceMethods, o PyMappingMethods,
respectivamente. Depende de usted completar esta estructura con los valores apropiados. Puede encontrar ejemplos del
uso de cada uno de estos en el directorio Objects de la distribución fuente de Python.
hashfunc tp_hash;
Esta función, si elige proporcionarla, debería retornar un número hash para una instancia de su tipo de datos. Aquí hay
un ejemplo simple:
static Py_hash_t
newdatatype_hash(newdatatypeobject *obj)
(continué en la próxima página)
Py_hash_t es un tipo entero con signo con un ancho que varia dependiendo de la plataforma.retornar -1 de tp_hash
indica un error, por lo que debe tener cuidado de evitar retornarlo cuando el cálculo de hash sea exitoso, como se vio
anteriormente.
ternaryfunc tp_call;
Esta función se llama cuando una instancia de su tipo de datos se «llama», por ejemplo, si obj1 es una instancia de su
tipo de datos y el script de Python contiene obj1('hello'), el controlador tp_call se invoca.
Esta función toma tres argumentos:
1. self es la instancia del tipo de datos que es el sujeto de la llamada. Si la llamada es obj1('hola'), entonces self
es obj1.
2. args es una tupla que contiene los argumentos de la llamada. Puede usar PyArg_ParseTuple() para extraer
los argumentos.
3. kwds es un diccionario de argumentos de palabras clave que se pasaron. Si no es NULL y admite argumentos de
palabras clave, use PyArg_ParseTupleAndKeywords() para extraer los argumentos. Si no desea admitir
argumentos de palabras clave y esto no es NULL, genere un TypeError con un mensaje que indique que los
argumentos de palabras clave no son compatibles.
Aquí hay una implementación de juguete tp_call:
static PyObject *
newdatatype_call(newdatatypeobject *obj, PyObject *args, PyObject *kwds)
{
PyObject *result;
const char *arg1;
const char *arg2;
const char *arg3;
/* Iterators */
getiterfunc tp_iter;
iternextfunc tp_iternext;
These functions provide support for the iterator protocol. Both handlers take exactly one parameter, the instance for
which they are being called, and return a new reference. In the case of an error, they should set an exception and return
NULL. tp_iter corresponds to the Python __iter__() method, while tp_iternext corresponds to the Python
__next__() method.
Cualquier objeto iterable debe implementar el manejador tp_iter, que debe retornar un objeto iterator. Aquí se aplican
las mismas pautas que para las clases de Python:
• Para colecciones (como listas y tuplas) que pueden admitir múltiples iteradores independientes, cada llamada debe
crear y retornar un nuevo iterador a tp_iter.
• Los objetos que solo se pueden iterar una vez (generalmente debido a los efectos secundarios de la iteración, como
los objetos de archivo) pueden implementar tp_iter retornando una nueva referencia a ellos mismos y, por lo
tanto, también deben implementar el manejador tp_iternext.
Cualquier objeto iterator debe implementar tanto tp_iter como tp_iternext. El manejador de un iterador
tp_iter debería retornar una nueva referencia al iterador. Su controlador tp_iternext debería retornar una nueva
referencia al siguiente objeto en la iteración, si hay uno. Si la iteración ha llegado al final, tp_iternext puede re-
tornar NULL sin establecer una excepción, o puede establecer StopIteration además para retornar NULL; evitar la
excepción puede producir un rendimiento ligeramente mejor. Si se produce un error real, tp_iternext siempre debe
establecer una excepción y retornar NULL.
Uno de los objetivos de la implementación de referencia débil de Python es permitir que cualquier tipo participe en el
mecanismo de referencia débil sin incurrir en la sobrecarga de objetos críticos para el rendimiento (como los números).
Ver también:
Documentación para el módulo weakref.
For an object to be weakly referencable, the extension type must set the Py_TPFLAGS_MANAGED_WEAKREF bit of
the tp_flags field. The legacy tp_weaklistoffset field should be left as zero.
Concretely, here is how the statically declared type object would look:
The only further addition is that tp_dealloc needs to clear any weak references (by calling
PyObject_ClearWeakRefs()):
static void
Trivial_dealloc(TrivialObject *self)
{
/* Clear weakrefs first before calling any destructors */
PyObject_ClearWeakRefs((PyObject *) self);
/* ... remainder of destruction code omitted for brevity ... */
Py_TYPE(self)->tp_free((PyObject *) self);
}
Para aprender a implementar cualquier método específico para su nuevo tipo de datos, obtenga el código fuente CPyt-
hon. Vaya al directorio Objects, luego busque en los archivos fuente C tp_ más la función que desee (por ejemplo,
tp_richcompare). Encontrará ejemplos de la función que desea implementar.
Cuando necesite verificar que un objeto es una instancia concreta del tipo que está implementando, use la función
PyObject_TypeCheck(). Una muestra de su uso podría ser algo como lo siguiente:
if (!PyObject_TypeCheck(some_object, &MyType)) {
PyErr_SetString(PyExc_TypeError, "arg #1 not a mything");
return NULL;
}
Ver también:
Descargue las versiones de origen de CPython. https://www.python.org/downloads/source/
El proyecto CPython en GitHub, donde se desarrolla el código fuente de CPython. https://github.com/python/
cpython
Una extensión C para CPython es una biblioteca compartida (por ejemplo, un archivo .so en Linux, .pyd en Windows),
que exporta una función de inicialización.
To be importable, the shared library must be available on PYTHONPATH, and must be named after the module name,
with an appropriate extension. When using setuptools, the correct filename is generated automatically.
La función de inicialización tiene la firma:
PyObject *PyInit_modulename(void)
It returns either a fully initialized module, or a PyModuleDef instance. See initializing-modules for details.
Para los módulos con nombres solo ASCII, la función debe llamarse PyInit_<modulename>, con <modulename>
reemplazado por el nombre del módulo. Cuando se usa multi-phase-initialization, se permiten nombres de módulos
que no sean ASCII. En este caso, el nombre de la función de inicialización es PyInitU_<modulename>, con
<modulename> codificado usando la codificación punycode de Python con guiones reemplazados por guiones bajos.
En Python:
def initfunc_name(name):
try:
suffix = b'_' + name.encode('ascii')
except UnicodeEncodeError:
suffix = b'U_' + name.encode('punycode').replace(b'-', b'_')
return b'PyInit' + suffix
Es posible exportar múltiples módulos desde una única biblioteca compartida definiendo múltiples funciones de ini-
cialización. Sin embargo, importarlos requiere el uso de enlaces simbólicos o un importador personalizado, porque de
forma predeterminada solo se encuentra la función correspondiente al nombre del archivo. Consulte la sección «Múltiples
módulos en una biblioteca» en PEP 489 para más detalles.
Python 3.12 and newer no longer come with distutils. Please refer to the setuptools documentation at https:
//setuptools.readthedocs.io/en/latest/setuptools.html to learn more about how build and distribute C/C++ extensions with
setuptools.
Este capítulo explica brevemente cómo crear un módulo de extensión de Windows para Python usando Microsoft Visual
C++, y sigue con información de fondo más detallada sobre cómo funciona. El material explicativo es útil tanto para el
programador de Windows que está aprendiendo a construir extensiones de Python como para el programador de Unix
interesado en producir software que se pueda construir con éxito tanto en Unix como en Windows.
Se alienta a los autores de módulos a utilizar el enfoque distutils para construir módulos de extensión, en lugar del descrito
en esta sección. Aún necesitará el compilador de C que se utilizó para construir Python; típicamente Microsoft Visual
C++.
Nota: Este capítulo menciona varios nombres de archivo que incluyen un número de versión codificado de Python. Estos
nombres de archivo se representan con el número de versión que se muestra como XY; en la práctica, 'X' será el número
de versión principal y 'Y' será el número de versión menor de la versión de Python con la que está trabajando. Por
ejemplo, si está utilizando Python 2.2.1, XY en realidad será 22.
There are two approaches to building extension modules on Windows, just as there are on Unix: use the setuptools
package to control the build process, or do things manually. The setuptools approach works well for most extensions;
documentation on using setuptools to build and package extension modules is available in Building C and C++
Extensions with setuptools. If you find you really need to do things manually, it may be instructive to study the project file
for the winsound standard library module.
Unix y Windows usan paradigmas completamente diferentes para la carga de código en tiempo de ejecución. Antes de
intentar construir un módulo que se pueda cargar dinámicamente, tenga en cuenta cómo funciona su sistema.
En Unix, un archivo de objeto compartido (.so) contiene código para ser utilizado por el programa, y también los nombres
de funciones y datos que espera encontrar en el programa. Cuando el archivo se une al programa, todas las referencias a
esas funciones y datos en el código del archivo se cambian para apuntar a las ubicaciones reales en el programa donde las
funciones y los datos se colocan en la memoria. Esto es básicamente una operación de enlace.
En Windows, un archivo de biblioteca de enlace dinámico (.dll) no tiene referencias colgantes. En cambio, un acceso
a funciones o datos pasa por una tabla de búsqueda. Por lo tanto, el código DLL no tiene que repararse en tiempo de
ejecución para referirse a la memoria del programa; en cambio, el código ya usa la tabla de búsqueda de la DLL, y la tabla
de búsqueda se modifica en tiempo de ejecución para apuntar a las funciones y los datos.
En Unix, solo hay un tipo de archivo de biblioteca (.a) que contiene código de varios archivos de objeto (.o). Durante
el paso de enlace para crear un archivo de objeto compartido (.so), el enlazador puede encontrar que no sabe dónde se
define un identificador. El enlazador lo buscará en los archivos de objetos en las bibliotecas; si lo encuentra, incluirá todo
el código de ese archivo de objeto.
En Windows, hay dos tipos de biblioteca, una biblioteca estática y una biblioteca de importación (ambas llamadas .lib).
Una biblioteca estática es como un archivo Unix .a; Contiene código para ser incluido según sea necesario. Una biblioteca
de importación se usa básicamente solo para asegurarle al enlazador que cierto identificador es legal y estará presente en el
programa cuando se cargue la DLL. Por lo tanto, el enlazador utiliza la información de la biblioteca de importación para
crear la tabla de búsqueda para usar identificadores que no están incluidos en la DLL. Cuando se vincula una aplicación
o una DLL, se puede generar una biblioteca de importación, que deberá usarse para todas las DLL futuras que dependan
de los símbolos en la aplicación o DLL.
Suponga que está creando dos módulos de carga dinámica, B y C, que deberían compartir otro bloque de código A. En
Unix, no pasaría A.a al enlazador para B.so y C.so; eso haría que se incluyera dos veces, de modo que B y C tengan
cada uno su propia copia. En Windows, compilar A.dll también compilará A.lib. Usted si pasa A.lib al enlazador
para B y C. A.lib no contiene código; solo contiene información que se usará en tiempo de ejecución para acceder al
código de A.
En Windows, usar una biblioteca de importación es como usar importar spam; le da acceso a los nombres de spam,
pero no crea una copia separada. En Unix, vincular con una biblioteca es más como from spam import*; crea una
copia separada.
Windows Python is built in Microsoft Visual C++; using other compilers may or may not work. The rest of this section
is MSVC++ specific.
Al crear archivos DLL en Windows, debe pasar pythonXY.lib al enlazador. Para construir dos DLL, spam y ni (que
usa funciones C que se encuentran en el spam), puede usar estos comandos:
El primer comando creó tres archivos: spam.obj, spam.dll y spam.lib. Spam.dll no contiene ninguna función
de Python (como PyArg_ParseTuple()), pero sabe cómo encontrar el código de Python gracias a pythonXY.
lib.
El segundo comando creó ni.dll (y .obj y .lib), que sabe cómo encontrar las funciones necesarias del spam, y
también del ejecutable de Python.
No todos los identificadores se exportan a la tabla de búsqueda. Si desea que cualquier otro módulo (incluido Python)
pueda ver sus identificadores, debe decir _declspec(dllexport), como en void _declspec(dllexport)
initspam(void) o PyObject_declspec(dllexport) *NiGetSpamData(void).
Developer Studio will throw in a lot of import libraries that you do not really need, adding about 100K to your execu-
table. To get rid of them, use the Project Settings dialog, Link tab, to specify ignore default libraries. Add the correct
msvcrtxx.lib to the list of libraries.
A veces, en lugar de crear una extensión que se ejecute dentro del intérprete de Python como la aplicación principal,
es conveniente incorporar el tiempo de ejecución de CPython dentro de una aplicación más grande. Esta sección cubre
algunos de los detalles involucrados en hacerlo con éxito.
Los capítulos anteriores discutieron cómo extender Python, es decir, cómo extender la funcionalidad de Python al ad-
juntarle una biblioteca de funciones C. También es posible hacerlo al revés: enriquezca su aplicación C/C++ incrustando
Python en ella. La incrustación proporciona a su aplicación la capacidad de implementar parte de la funcionalidad de
su aplicación en Python en lugar de C o C++. Esto se puede usar para muchos propósitos; Un ejemplo sería permitir a
los usuarios adaptar la aplicación a sus necesidades escribiendo algunos scripts en Python. También puede usarlo usted
mismo si parte de la funcionalidad se puede escribir en Python más fácilmente.
Incrustar Python es similar a extenderlo, pero no del todo. La diferencia es que cuando extiende Python, el programa
principal de la aplicación sigue siendo el intérprete de Python, mientras que si incrusta Python, el programa principal
puede no tener nada que ver con Python — en cambio, algunas partes de la aplicación ocasionalmente llaman al Intérprete
de Python para ejecutar algún código de Python.
Entonces, si está incrustando Python, está proporcionando su propio programa principal. Una de las cosas que tie-
ne que hacer este programa principal es inicializar el intérprete de Python. Como mínimo, debe llamar a la función
Py_Initialize(). Hay llamadas opcionales para pasar argumentos de línea de comandos a Python. Luego, puede
llamar al intérprete desde cualquier parte de la aplicación.
Hay varias formas diferentes de llamar al intérprete: puede pasar una cadena que contiene declaraciones de Python a
PyRun_SimpleString(), o puede pasar un puntero de archivo estándar y un nombre de archivo (solo para identi-
ficación en mensajes de error) a PyRun_SimpleFile(). También puede llamar a las operaciones de nivel inferior
descritas en los capítulos anteriores para construir y usar objetos de Python.
Ver también:
c-api-index Los detalles de la interfaz C de Python se dan en este manual. Una gran cantidad de información necesaria
se puede encontrar aquí.
63
Extending and Embedding Python, Versión 3.12.0
La forma más simple de incrustar Python es el uso de la interfaz de muy alto nivel. Esta interfaz está diseñada para
ejecutar un script de Python sin necesidad de interactuar directamente con la aplicación. Esto puede usarse, por ejemplo,
para realizar alguna operación en un archivo.
#define PY_SSIZE_T_CLEAN
#include <Python.h>
int
main(int argc, char *argv[])
{
wchar_t *program = Py_DecodeLocale(argv[0], NULL);
if (program == NULL) {
fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
exit(1);
}
Py_SetProgramName(program); /* optional but recommended */
Py_Initialize();
PyRun_SimpleString("from time import time,ctime\n"
"print('Today is', ctime(time()))\n");
if (Py_FinalizeEx() < 0) {
exit(120);
}
PyMem_RawFree(program);
return 0;
}
La función Py_SetProgramName() debe llamarse antes de Py_Initialize() para informar al intérprete sobre
las rutas a las bibliotecas de tiempo de ejecución de Python. A continuación, el intérprete de Python se inicializa con
Py_Initialize(), seguido de la ejecución de un script Python codificado que imprime la fecha y la hora. Luego,
la llamada Py_FinalizeEx() cierra el intérprete, seguido por el final del programa. En un programa real, es posible
que desee obtener el script de Python de otra fuente, tal vez una rutina de editor de texto, un archivo o una base de datos.
Obtener el código Python de un archivo se puede hacer mejor usando la función PyRun_SimpleFile(), que le ahorra
la molestia de asignar espacio de memoria y cargar el contenido del archivo.
3.1.2 Más allá de la incrustación de muy alto nivel: una visión general
La interfaz de alto nivel le permite ejecutar piezas arbitrarias de código Python desde su aplicación, pero el intercambio
de valores de datos es bastante engorroso, por decir lo menos. Si lo desea, debe usar llamadas de nivel inferior. A costa
de tener que escribir más código C, puede lograr casi cualquier cosa.
Cabe señalar que extender Python e incrustar Python es la misma actividad, a pesar de la intención diferente. La mayoría
de los temas tratados en los capítulos anteriores siguen siendo válidos. Para mostrar esto, considere lo que realmente hace
el código de extensión de Python a C:
1. Convierte valores de datos de Python a C,
2. Realice una llamada de función a una rutina C usando los valores convertidos, y
3. Convierte los valores de datos de la llamada de C a Python.
Al incrustar Python, el código de interfaz hace:
1. Convierte valores de datos de C a Python,
2. Realice una llamada de función a una rutina de interfaz de Python utilizando los valores convertidos, y
3. Convierte los valores de datos de la llamada de Python a C.
Como puede ver, los pasos de conversión de datos simplemente se intercambian para acomodar la dirección diferente de
la transferencia de idiomas cruzados. La única diferencia es la rutina que llama entre ambas conversiones de datos. Al
extender, llama a una rutina C, al incrustar, llama a una rutina Python.
Este capítulo no discutirá cómo convertir datos de Python a C y viceversa. Además, se supone que se entiende el uso
adecuado de las referencias y el tratamiento de errores. Dado que estos aspectos no difieren de extender el intérprete,
puede consultar los capítulos anteriores para obtener la información requerida.
El primer programa tiene como objetivo ejecutar una función en un script Python. Al igual que en la sección sobre la
interfaz de muy alto nivel, el intérprete de Python no interactúa directamente con la aplicación (pero eso cambiará en la
siguiente sección).
El código para ejecutar una función definida en un script de Python es:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
int
main(int argc, char *argv[])
{
PyObject *pName, *pModule, *pFunc;
PyObject *pArgs, *pValue;
int i;
if (argc < 3) {
fprintf(stderr,"Usage: call pythonfile funcname [args]\n");
return 1;
}
Py_Initialize();
pName = PyUnicode_DecodeFSDefault(argv[1]);
/* Error checking of pName left out */
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
pFunc = PyObject_GetAttrString(pModule, argv[2]);
/* pFunc is a new reference */
Este código carga un script de Python usando argv[1] y llama a la función nombrada en argv[2]. Sus argumentos
enteros son los otros valores del arreglo argv. Si usted compila y enlaza este programa (llamemos al ejecutable terminado
call), y úselo para ejecutar un script Python, como:
def multiply(a,b):
print("Will compute", a, "times", b)
c = 0
for i in range(0, a):
c = c + b
return c
Aunque el programa es bastante grande por su funcionalidad, la mayor parte del código es para la conversión de datos
entre Python y C, y para informes de errores. La parte interesante con respecto a incrustar Python comienza con:
Py_Initialize();
pName = PyUnicode_DecodeFSDefault(argv[1]);
/* Error checking of pName left out */
pModule = PyImport_Import(pName);
Después de inicializar el intérprete, el script se carga usando PyImport_Import(). Esta rutina necesita una cadena
Python como argumento, que se construye utilizando la rutina de conversión de datos PyUnicode_FromString().
Una vez que se carga el script, el nombre que estamos buscando se recupera usando PyObject_GetAttrString().
Si el nombre existe y el objeto retornado es invocable, puede asumir con seguridad que es una función. Luego, el programa
continúa construyendo una tupla de argumentos como de costumbre. La llamada a la función Python se realiza con:
Al regresar la función, pValue es NULL o contiene una referencia al valor de retorno de la función. Asegúrese de liberar
la referencia después de examinar el valor.
Hasta ahora, el intérprete de Python incorporado no tenía acceso a la funcionalidad de la aplicación misma. La API de
Python lo permite al extender el intérprete incorporado. Es decir, el intérprete incorporado se amplía con las rutinas
proporcionadas por la aplicación. Si bien suena complejo, no es tan malo. Simplemente olvide por un momento que la
aplicación inicia el intérprete de Python. En cambio, considere que la aplicación es un conjunto de subrutinas y escriba
un código de pegamento que le otorgue a Python acceso a esas rutinas, al igual que escribiría una extensión normal de
Python. Por ejemplo:
static PyObject*
PyInit_emb(void)
{
return PyModule_Create(&EmbModule);
}
Inserte el código anterior justo encima de la función main(). Además, inserte las siguientes dos declaraciones antes de
la llamada a Py_Initialize():
numargs = argc;
PyImport_AppendInittab("emb", &PyInit_emb);
These two lines initialize the numargs variable, and make the emb.numargs() function accessible to the embedded
Python interpreter. With these extensions, the Python script can do things like
import emb
print("Number of arguments", emb.numargs())
En una aplicación real, los métodos expondrán una API de la aplicación a Python.
También es posible incrustar Python en un programa C++; precisamente cómo se hace esto dependerá de los detalles del
sistema C++ utilizado; en general, necesitará escribir el programa principal en C++ y usar el compilador de C++ para
compilar y vincular su programa. No es necesario volver a compilar Python usando C++.
No es necesariamente trivial encontrar los indicadores correctos para pasar a su compilador (y enlazador) para incrustar
el intérprete de Python en su aplicación, particularmente porque Python necesita cargar módulos de biblioteca imple-
mentados como extensiones dinámicas en C (archivos .so) enlazados en su contra.
Para conocer los indicadores necesarios del compilador y el enlazador, puede ejecutar el script pythonX.Y-config
que se genera como parte del proceso de instalación (también puede estar disponible un script python3-config )
Este script tiene varias opciones, de las cuales las siguientes serán directamente útiles para usted:
• pythonX.Y-config --cflags le dará las banderas recomendadas al compilar:
$ /opt/bin/python3.11-config --cflags
-I/opt/include/python3.11 -I/opt/include/python3.11 -Wsign-compare -DNDEBUG -g -
,→fwrapv -O3 -Wall
• pythonX.Y-config --ldflags --embed will give you the recommended flags when linking:
Nota: Para evitar confusiones entre varias instalaciones de Python (y especialmente entre el sistema Python y su propio
Python compilado), se recomienda que use la ruta absoluta a pythonX.Y-config, como en el ejemplo anterior.
Si este procedimiento no funciona para usted (no se garantiza que funcione para todas las plataformas tipo Unix; sin
embargo, le damos la bienvenida informes de errores) deberá leer la documentación de su sistema sobre dinámica vincu-
lar o examinar Python Makefile (use sysconfig.get_makefile_filename() para encontrar su ubicación)
y las opciones de compilación. En este caso, el módulo sysconfig es una herramienta útil para extraer mediante
programación los valores de configuración que querrá combinar. Por ejemplo:
Glosario
>>> El prompt en el shell interactivo de Python por omisión. Frecuentemente vistos en ejemplos de código que pueden
ser ejecutados interactivamente en el intérprete.
... Puede referirse a:
• El prompt en el shell interactivo de Python por omisión cuando se ingresa código para un bloque indentado de
código, y cuando se encuentra entre dos delimitadores que emparejan (paréntesis, corchetes, llaves o comillas
triples), o después de especificar un decorador.
• La constante incorporada Ellipsis.
2to3 Una herramienta que intenta convertir código de Python 2.x a Python 3.x arreglando la mayoría de las incompati-
bilidades que pueden ser detectadas analizando el código y recorriendo el árbol de análisis sintáctico.
2to3 está disponible en la biblioteca estándar como lib2to3; un punto de entrada independiente es provisto como
Tools/scripts/2to3. Vea 2to3-reference.
clase base abstracta Las clases base abstractas (ABC, por sus siglas en inglés Abstract Base Class) complementan al
duck-typing brindando un forma de definir interfaces con técnicas como hasattr() que serían confusas o su-
tilmente erróneas (por ejemplo con magic methods). Las ABC introduce subclases virtuales, las cuales son clases
que no heredan desde una clase pero aún así son reconocidas por isinstance() y issubclass(); vea la
documentación del módulo abc. Python viene con muchas ABC incorporadas para las estructuras de datos( en el
módulo collections.abc), números (en el módulo numbers ) , flujos de datos (en el módulo io ) , busca-
dores y cargadores de importaciones (en el módulo importlib.abc ) . Puede crear sus propios ABCs con el
módulo abc.
anotación Una etiqueta asociada a una variable, atributo de clase, parámetro de función o valor de retorno, usado por
convención como un type hint.
Las anotaciones de variables no pueden ser accedidas en tiempo de ejecución, pero las anotaciones de variables
globales, atributos de clase, y funciones son almacenadas en el atributo especial __annotations__ de módulos,
clases y funciones, respectivamente.
Consulte variable annotation, function annotation, PEP 484 y PEP 526, que describen esta funcionalidad. Consulte
también annotations-howto para conocer las mejores prácticas sobre cómo trabajar con anotaciones.
argumento Un valor pasado a una function (o method) cuando se llama a la función. Hay dos clases de argumentos:
71
Extending and Embedding Python, Versión 3.12.0
• argumento nombrado: es un argumento precedido por un identificador (por ejemplo, nombre=) en una llama-
da a una función o pasado como valor en un diccionario precedido por **. Por ejemplo 3 y 5 son argumentos
nombrados en las llamadas a complex():
complex(real=3, imag=5)
complex(**{'real': 3, 'imag': 5})
• argumento posicional son aquellos que no son nombrados. Los argumentos posicionales deben aparecer al
principio de una lista de argumentos o ser pasados como elementos de un iterable precedido por *. Por
ejemplo, 3 y 5 son argumentos posicionales en las siguientes llamadas:
complex(3, 5)
complex(*(3, 5))
Los argumentos son asignados a las variables locales en el cuerpo de la función. Vea en la sección calls las reglas
que rigen estas asignaciones. Sintácticamente, cualquier expresión puede ser usada para representar un argumento;
el valor evaluado es asignado a la variable local.
Vea también el parameter en el glosario, la pregunta frecuente la diferencia entre argumentos y parámetros, y PEP
362.
administrador asincrónico de contexto An object which controls the environment seen in an async with statement
by defining __aenter__() and __aexit__() methods. Introduced by PEP 492.
generador asincrónico Una función que retorna un asynchronous generator iterator. Es similar a una función corrutina
definida con async def excepto que contiene expresiones yield para producir series de variables usadas en
un ciclo async for.
Usualmente se refiere a una función generadora asincrónica, pero puede referirse a un iterador generador asincrónico
en ciertos contextos. En aquellos casos en los que el significado no está claro, usar los términos completos evita la
ambigüedad.
Una función generadora asincrónica puede contener expresiones await así como sentencias async for, y
async with.
iterador generador asincrónico Un objeto creado por una función asynchronous generator.
This is an asynchronous iterator which when called using the __anext__() method returns an awaitable object
which will execute the body of the asynchronous generator function until the next yield expression.
Each yield temporarily suspends processing, remembering the location execution state (including local variables
and pending try-statements). When the asynchronous generator iterator effectively resumes with another awaitable
returned by __anext__(), it picks up where it left off. See PEP 492 and PEP 525.
iterable asincrónico An object, that can be used in an async for statement. Must return an asynchronous iterator
from its __aiter__() method. Introduced by PEP 492.
iterador asincrónico An object that implements the __aiter__() and __anext__() methods. __anext__()
must return an awaitable object. async for resolves the awaitables returned by an asynchronous iterator’s
__anext__() method until it raises a StopAsyncIteration exception. Introduced by PEP 492.
atributo A value associated with an object which is usually referenced by name using dotted expressions. For example,
if an object o has an attribute a it would be referenced as o.a.
It is possible to give an object an attribute whose name is not an identifier as defined by identifiers, for example
using setattr(), if the object allows it. Such an attribute will not be accessible using a dotted expression, and
would instead need to be retrieved with getattr().
a la espera An object that can be used in an await expression. Can be a coroutine or an object with an __await__()
method. See also PEP 492.
72 Apéndice A. Glosario
Extending and Embedding Python, Versión 3.12.0
BDFL Sigla de Benevolent Dictator For Life, benevolente dictador vitalicio, es decir Guido van Rossum, el creador de
Python.
archivo binario Un file object capaz de leer y escribir objetos tipo binarios. Ejemplos de archivos binarios son los abiertos
en modo binario ('rb', 'wb' o 'rb+'), sys.stdin.buffer, sys.stdout.buffer, e instancias de
io.BytesIO y de gzip.GzipFile.
Vea también text file para un objeto archivo capaz de leer y escribir objetos str.
referencia prestada In Python’s C API, a borrowed reference is a reference to an object, where the code using the
object does not own the reference. It becomes a dangling pointer if the object is destroyed. For example, a garbage
collection can remove the last strong reference to the object and so destroy it.
Se recomienda llamar a Py_INCREF() en la referencia prestada para convertirla en una referencia fuerte in
situ, excepto cuando el objeto no se puede destruir antes del último uso de la referencia prestada. La función
Py_NewRef() se puede utilizar para crear una nueva referencia fuerte.
objetos tipo binarios Un objeto que soporta bufferobjects y puede exportar un búfer C-contiguous. Esto incluye todas
los objetos bytes, bytearray, y array.array, así como muchos objetos comunes memoryview. Los
objetos tipo binarios pueden ser usados para varias operaciones que usan datos binarios; éstas incluyen compresión,
salvar a archivos binarios, y enviarlos a través de un socket.
Algunas operaciones necesitan que los datos binarios sean mutables. La documentación frecuentemente se refie-
re a éstos como «objetos tipo binario de lectura y escritura». Ejemplos de objetos de búfer mutables incluyen a
bytearray y memoryview de la bytearray. Otras operaciones que requieren datos binarios almacenados
en objetos inmutables («objetos tipo binario de sólo lectura»); ejemplos de éstos incluyen bytes y memoryview
del objeto bytes.
bytecode El código fuente Python es compilado en bytecode, la representación interna de un programa python en el
intérprete CPython. El bytecode también es guardado en caché en los archivos .pyc de tal forma que ejecutar el
mismo archivo es más fácil la segunda vez (la recompilación desde el código fuente a bytecode puede ser evitada).
Este «lenguaje intermedio» deberá corren en una virtual machine que ejecute el código de máquina correspondiente
a cada bytecode. Note que los bytecodes no tienen como requisito trabajar en las diversas máquina virtuales de
Python, ni de ser estable entre versiones Python.
Una lista de las instrucciones en bytecode está disponible en la documentación de el módulo dis.
callable A callable is an object that can be called, possibly with a set of arguments (see argument), with the following
syntax:
A function, and by extension a method, is a callable. An instance of a class that implements the __call__()
method is also a callable.
retrollamada Una función de subrutina que se pasa como un argumento para ejecutarse en algún momento en el futuro.
clase Una plantilla para crear objetos definidos por el usuario. Las definiciones de clase normalmente contienen defini-
ciones de métodos que operan una instancia de la clase.
variable de clase Una variable definida en una clase y prevista para ser modificada sólo a nivel de clase (es decir, no en
una instancia de la clase).
número complejo Una extensión del sistema familiar de número reales en el cual los números son expresados como la
suma de una parte real y una parte imaginaria. Los números imaginarios son múltiplos de la unidad imaginaria (la
raíz cuadrada de -1), usualmente escrita como i en matemáticas o j en ingeniería. Python tiene soporte incor-
porado para números complejos, los cuales son escritos con la notación mencionada al final.; la parte imaginaria
es escrita con un sufijo j, por ejemplo, 3+1j. Para tener acceso a los equivalentes complejos del módulo math
module, use cmath. El uso de números complejos es matemática bastante avanzada. Si no le parecen necesarios,
puede ignorarlos sin inconvenientes.
73
Extending and Embedding Python, Versión 3.12.0
administrador de contextos Un objeto que controla el entorno en la sentencia with definiendo los métodos
__enter__() y __exit__(). Vea PEP 343.
variable de contexto Una variable que puede tener diferentes valores dependiendo del contexto. Esto es similar a un
almacenamiento de hilo local Thread-Local Storage en el cual cada hilo de ejecución puede tener valores diferentes
para una variable. Sin embargo, con las variables de contexto, podría haber varios contextos en un hilo de ejecución
y el uso principal de las variables de contexto es mantener registro de las variables en tareas concurrentes asíncronas.
Vea contextvars.
contiguo Un búfer es considerado contiguo con precisión si es C-contiguo o Fortran contiguo. Los búferes cero dimen-
sionales con C y Fortran contiguos. En los arreglos unidimensionales, los ítems deben ser dispuestos en memoria
uno siguiente al otro, ordenados por índices que comienzan en cero. En arreglos unidimensionales C-contiguos, el
último índice varía más velozmente en el orden de las direcciones de memoria. Sin embargo, en arreglos Fortran
contiguos, el primer índice vería más rápidamente.
corrutina Las corrutinas son una forma más generalizadas de las subrutinas. A las subrutinas se ingresa por un punto y
se sale por otro punto. Las corrutinas pueden se iniciadas, finalizadas y reanudadas en muchos puntos diferentes.
Pueden ser implementadas con la sentencia async def. Vea además PEP 492.
función corrutina Un función que retorna un objeto coroutine . Una función corrutina puede ser definida con la sentencia
async def, y puede contener las palabras claves await, async for, y async with. Las mismas son
introducidas en PEP 492.
CPython La implementación canónica del lenguaje de programación Python, como se distribuye en python.org. El tér-
mino «CPython» es usado cuando es necesario distinguir esta implementación de otras como Jython o IronPython.
decorador Una función que retorna otra función, usualmente aplicada como una función de transformación empleando
la sintaxis @envoltorio. Ejemplos comunes de decoradores son classmethod() y staticmethod().
La sintaxis del decorador es meramente azúcar sintáctico, las definiciones de las siguientes dos funciones son se-
mánticamente equivalentes:
def f(arg):
...
f = staticmethod(f)
@staticmethod
def f(arg):
...
El mismo concepto existe para clases, pero son menos usadas. Vea la documentación de function definitions y class
definitions para mayor detalle sobre decoradores.
descriptor Cualquier objeto que define los métodos __get__(), __set__(), o __delete__(). Cuando un atri-
buto de clase es un descriptor, su conducta enlazada especial es disparada durante la búsqueda del atributo. Nor-
malmente, usando a.b para consultar, establecer o borrar un atributo busca el objeto llamado b en el diccionario de
clase de a, pero si b es un descriptor, el respectivo método descriptor es llamado. Entender descriptores es clave
para lograr una comprensión profunda de Python porque son la base de muchas de las capacidades incluyendo
funciones, métodos, propiedades, métodos de clase, métodos estáticos, y referencia a súper clases.
Para obtener más información sobre los métodos de los descriptores, consulte descriptors o Guía práctica de uso
de los descriptores.
diccionario Un arreglo asociativo, con claves arbitrarias que son asociadas a valores. Las claves pueden ser cualquier
objeto con los métodos __hash__() y __eq__() . Son llamadas hash en Perl.
comprensión de diccionarios Una forma compacta de procesar todos o parte de los elementos en un iterable y retornar
un diccionario con los resultados. results = {n: n ** 2 for n in range(10)} genera un diccio-
nario que contiene la clave n asignada al valor n ** 2. Ver comprehensions.
74 Apéndice A. Glosario
Extending and Embedding Python, Versión 3.12.0
vista de diccionario Los objetos retornados por los métodos dict.keys(), dict.values(), y dict.items()
son llamados vistas de diccionarios. Proveen una vista dinámica de las entradas de un diccionario, lo que significa
que cuando el diccionario cambia, la vista refleja éstos cambios. Para forzar a la vista de diccionario a convertirse
en una lista completa, use list(dictview). Vea dict-views.
docstring Una cadena de caracteres literal que aparece como la primera expresión en una clase, función o módulo.
Aunque es ignorada cuando se ejecuta, es reconocida por el compilador y puesta en el atributo __doc__ de la
clase, función o módulo comprendida. Como está disponible mediante introspección, es el lugar canónico para
ubicar la documentación del objeto.
tipado de pato Un estilo de programación que no revisa el tipo del objeto para determinar si tiene la interfaz correcta; en
vez de ello, el método o atributo es simplemente llamado o usado («Si se ve como un pato y grazna como un pato,
debe ser un pato»). Enfatizando las interfaces en vez de hacerlo con los tipos específicos, un código bien diseñado
pues tener mayor flexibilidad permitiendo la sustitución polimórfica. El tipado de pato duck-typing evita usar pruebas
llamando a type() o isinstance(). (Nota: si embargo, el tipado de pato puede ser complementado con
abstract base classes. En su lugar, generalmente pregunta con hasattr() o EAFP.
EAFP Del inglés Easier to ask for forgiveness than permission, es más fácil pedir perdón que pedir permiso. Este estilo
de codificación común en Python asume la existencia de claves o atributos válidos y atrapa las excepciones si esta
suposición resulta falsa. Este estilo rápido y limpio está caracterizado por muchas sentencias try y except. Esta
técnica contrasta con estilo LBYL usual en otros lenguajes como C.
expresión Una construcción sintáctica que puede ser evaluada, hasta dar un valor. En otras palabras, una expresión es una
acumulación de elementos de expresión tales como literales, nombres, accesos a atributos, operadores o llamadas
a funciones, todos ellos retornando valor. A diferencia de otros lenguajes, no toda la sintaxis del lenguaje son
expresiones. También hay statements que no pueden ser usadas como expresiones, como la while. Las asignaciones
también son sentencias, no expresiones.
módulo de extensión Un módulo escrito en C o C++, usando la API para C de Python para interactuar con el núcleo y
el código del usuario.
f-string Son llamadas f-strings las cadenas literales que usan el prefijo 'f' o 'F', que es una abreviatura para formatted
string literals. Vea también PEP 498.
objeto archivo Un objeto que expone una API orientada a archivos (con métodos como read() o write()) al objeto
subyacente. Dependiendo de la forma en la que fue creado, un objeto archivo, puede mediar el acceso a un archivo
real en el disco u otro tipo de dispositivo de almacenamiento o de comunicación (por ejemplo, entrada/salida
estándar, búfer de memoria, sockets, pipes, etc.). Los objetos archivo son también denominados objetos tipo archivo
o flujos.
Existen tres categorías de objetos archivo: crudos raw archivos binarios, con búfer archivos binarios y archivos de
texto. Sus interfaces son definidas en el módulo io. La forma canónica de crear objetos archivo es usando la función
open().
objetos tipo archivo Un sinónimo de file object.
codificación del sistema de archivos y manejador de errores Controlador de errores y codificación utilizado por Pyt-
hon para decodificar bytes del sistema operativo y codificar Unicode en el sistema operativo.
La codificación del sistema de archivos debe garantizar la decodificación exitosa de todos los bytes por debajo de
128. Si la codificación del sistema de archivos no proporciona esta garantía, las funciones de API pueden lanzar
UnicodeError.
Las funciones sys.getfilesystemencoding() y sys.getfilesystemencodeerrors() se pue-
den utilizar para obtener la codificación del sistema de archivos y el controlador de errores.
La codificación del sistema de archivos y el manejador de errores se configuran al inicio de Python mediante la
función PyConfig_Read(): consulte los miembros filesystem_encoding y filesystem_errors
de PyConfig.
See also the locale encoding.
75
Extending and Embedding Python, Versión 3.12.0
buscador Un objeto que trata de encontrar el loader para el módulo que está siendo importado.
Desde la versión 3.3 de Python, existen dos tipos de buscadores: meta buscadores de ruta para usar con sys.
meta_path, y buscadores de entradas de rutas para usar con sys.path_hooks.
Vea PEP 302, PEP 420 y PEP 451 para mayores detalles.
división entera Una división matemática que se redondea hacia el entero menor más cercano. El operador de la división
entera es //. Por ejemplo, la expresión 11 // 4 evalúa 2 a diferencia del 2.75 retornado por la verdadera
división de números flotantes. Note que (-11) // 4 es -3 porque es -2.75 redondeado para abajo. Ver PEP
238.
función Una serie de sentencias que retornan un valor al que las llama. También se le puede pasar cero o más argumentos
los cuales pueden ser usados en la ejecución de la misma. Vea también parameter, method, y la sección function.
anotación de función Una annotation del parámetro de una función o un valor de retorno.
Las anotaciones de funciones son usadas frecuentemente para indicadores de tipo, por ejemplo, se espera que una
función tome dos argumentos de clase int y también se espera que retorne dos valores int:
recolección de basura El proceso de liberar la memoria de lo que ya no está en uso. Python realiza recolección de basura
(garbage collection) llevando la cuenta de las referencias, y el recogedor de basura cíclico es capaz de detectar y
romper las referencias cíclicas. El recogedor de basura puede ser controlado mediante el módulo gc .
generador Una función que retorna un generator iterator. Luce como una función normal excepto que contiene la ex-
presión yield para producir series de valores utilizables en un bucle for o que pueden ser obtenidas una por una
con la función next().
Usualmente se refiere a una función generadora, pero puede referirse a un iterador generador en ciertos contextos.
En aquellos casos en los que el significado no está claro, usar los términos completos evita la ambigüedad.
iterador generador Un objeto creado por una función generator.
Cada yield suspende temporalmente el procesamiento, recordando el estado de ejecución local (incluyendo las
variables locales y las sentencias try pendientes). Cuando el «iterador generado» vuelve, retoma donde ha dejado,
a diferencia de lo que ocurre con las funciones que comienzan nuevamente con cada invocación.
expresión generadora Una expresión que retorna un iterador. Luce como una expresión normal seguida por la cláusula
for definiendo así una variable de bucle, un rango y una cláusula opcional if. La expresión combinada genera
valores para la función contenedora:
76 Apéndice A. Glosario
Extending and Embedding Python, Versión 3.12.0
función genérica Una función compuesta de muchas funciones que implementan la misma operación para diferentes
tipos. Qué implementación deberá ser usada durante la llamada a la misma es determinado por el algoritmo de
despacho.
Vea también la entrada de glosario single dispatch, el decorador functools.singledispatch(), y PEP
443.
tipos genéricos A type that can be parameterized; typically a container class such as list or dict. Used for type hints
and annotations.
For more details, see generic alias types, PEP 483, PEP 484, PEP 585, and the typing module.
GIL Vea global interpreter lock.
bloqueo global del intérprete Mecanismo empleado por el intérprete CPython para asegurar que sólo un hilo ejecute
el bytecode Python por vez. Esto simplifica la implementación de CPython haciendo que el modelo de objetos
(incluyendo algunos críticos como dict) están implícitamente a salvo de acceso concurrente. Bloqueando el in-
térprete completo se simplifica hacerlo multi-hilos, a costa de mucho del paralelismo ofrecido por las máquinas
con múltiples procesadores.
However, some extension modules, either standard or third-party, are designed so as to release the GIL when doing
computationally intensive tasks such as compression or hashing. Also, the GIL is always released when doing I/O.
Esfuerzos previos hechos para crear un intérprete «sin hilos» (uno que bloquee los datos compartidos con una
granularidad mucho más fina) no han sido exitosos debido a que el rendimiento sufrió para el caso más común
de un solo procesador. Se cree que superar este problema de rendimiento haría la implementación mucho más
compleja y por tanto, más costosa de mantener.
hash-based pyc Un archivo cache de bytecode que usa el hash en vez de usar el tiempo de la última modificación del
archivo fuente correspondiente para determinar su validez. Vea pyc-invalidation.
hashable Un objeto es hashable si tiene un valor de hash que nunca cambiará durante su tiempo de vida (necesita un
método __hash__() ), y puede ser comparado con otro objeto (necesita el método __eq__() ). Los objetos
hashables que se comparan iguales deben tener el mismo número hash.
Ser hashable hace a un objeto utilizable como clave de un diccionario y miembro de un set, porque éstas estructuras
de datos usan los valores de hash internamente.
La mayoría de los objetos inmutables incorporados en Python son hashables; los contenedores mutables (como las
listas o los diccionarios) no lo son; los contenedores inmutables (como tuplas y conjuntos frozensets) son hashables
si sus elementos son hashables . Los objetos que son instancias de clases definidas por el usuario son hashables
por defecto. Todos se comparan como desiguales (excepto consigo mismos), y su valor de hash está derivado de su
función id().
IDLE An Integrated Development and Learning Environment for Python. idle is a basic editor and interpreter environ-
ment which ships with the standard distribution of Python.
inmutable Un objeto con un valor fijo. Los objetos inmutables son números, cadenas y tuplas. Éstos objetos no pueden
ser alterados. Un nuevo objeto debe ser creado si un valor diferente ha de ser guardado. Juegan un rol importante
en lugares donde es necesario un valor de hash constante, por ejemplo como claves de un diccionario.
ruta de importación Una lista de las ubicaciones (o entradas de ruta) que son revisadas por path based finder al impor-
tar módulos. Durante la importación, ésta lista de localizaciones usualmente viene de sys.path, pero para los
subpaquetes también puede incluir al atributo __path__ del paquete padre.
importar El proceso mediante el cual el código Python dentro de un módulo se hace alcanzable desde otro código Python
en otro módulo.
importador Un objeto que buscan y lee un módulo; un objeto que es tanto finder como loader.
interactivo Python tiene un intérprete interactivo, lo que significa que puede ingresar sentencias y expresiones en el
prompt del intérprete, ejecutarlos de inmediato y ver sus resultados. Sólo ejecute python sin argumentos (podría
77
Extending and Embedding Python, Versión 3.12.0
seleccionarlo desde el menú principal de su computadora). Es una forma muy potente de probar nuevas ideas o
inspeccionar módulos y paquetes (recuerde help(x)).
interpretado Python es un lenguaje interpretado, a diferencia de uno compilado, a pesar de que la distinción puede ser
difusa debido al compilador a bytecode. Esto significa que los archivos fuente pueden ser corridos directamente, sin
crear explícitamente un ejecutable que es corrido luego. Los lenguajes interpretados típicamente tienen ciclos de
desarrollo y depuración más cortos que los compilados, sin embargo sus programas suelen correr más lentamente.
Vea también interactive.
apagado del intérprete Cuando se le solicita apagarse, el intérprete Python ingresa a un fase especial en la cual gra-
dualmente libera todos los recursos reservados, como módulos y varias estructuras internas críticas. También hace
varias llamadas al recolector de basura. Esto puede disparar la ejecución de código de destructores definidos por
el usuario o weakref callbacks. El código ejecutado durante la fase de apagado puede encontrar varias excepciones
debido a que los recursos que necesita pueden no funcionar más (ejemplos comunes son los módulos de bibliotecas
o los artefactos de advertencias warnings machinery)
La principal razón para el apagado del intérpreter es que el módulo __main__ o el script que estaba corriendo
termine su ejecución.
iterable An object capable of returning its members one at a time. Examples of iterables include all sequence types (such
as list, str, and tuple) and some non-sequence types like dict, file objects, and objects of any classes you
define with an __iter__() method or with a __getitem__() method that implements sequence semantics.
Los iterables pueden ser usados en el bucle for y en muchos otros sitios donde una secuencia es necesaria (zip(),
map(), …). Cuando un objeto iterable es pasado como argumento a la función incorporada iter(), retorna un
iterador para el objeto. Este iterador pasa así el conjunto de valores. Cuando se usan iterables, normalmente no es
necesario llamar a la función iter() o tratar con los objetos iteradores usted mismo. La sentencia for lo hace
automáticamente por usted, creando un variable temporal sin nombre para mantener el iterador mientras dura el
bucle. Vea también iterator, sequence, y generator.
iterador Un objeto que representa un flujo de datos. Llamadas repetidas al método __next__() del iterador (o al
pasar la función incorporada next()) retorna ítems sucesivos del flujo. Cuando no hay más datos disponibles, una
excepción StopIteration es disparada. En este momento, el objeto iterador está exhausto y cualquier llamada
posterior al método __next__() sólo dispara otra vez StopIteration. Los iteradores necesitan tener un
método __iter__() que retorna el objeto iterador mismo así cada iterador es también un iterable y puede ser
usado en casi todos los lugares donde los iterables son aceptados. Una excepción importante es el código que intenta
múltiples pases de iteración. Un objeto contenedor (como la list) produce un nuevo iterador cada vez que pasa
a una función iter() o se usa en un bucle for. Intentar ésto con un iterador simplemente retornaría el mismo
objeto iterador exhausto usado en previas iteraciones, haciéndolo aparecer como un contenedor vacío.
Puede encontrar más información en typeiter.
Detalles de implementación de CPython: CPython does not consistently apply the requirement that an iterator
define __iter__().
función clave Una función clave o una función de colación es un invocable que retorna un valor usado para el ordena-
miento o clasificación. Por ejemplo, locale.strxfrm() es usada para producir claves de ordenamiento que
se adaptan a las convenciones específicas de ordenamiento de un locale.
Cierta cantidad de herramientas de Python aceptan funciones clave para controlar como los elementos son orde-
nados o agrupados. Incluyendo a min(), max(), sorted(), list.sort(), heapq.merge(), heapq.
nsmallest(), heapq.nlargest(), y itertools.groupby().
There are several ways to create a key function. For example. the str.lower() method can serve as a key
function for case insensitive sorts. Alternatively, a key function can be built from a lambda expression such
as lambda r: (r[0], r[2]). Also, operator.attrgetter(), operator.itemgetter(), and
operator.methodcaller() are three key function constructors. See the Sorting HOW TO for examples of
how to create and use key functions.
argumento nombrado Vea argument.
78 Apéndice A. Glosario
Extending and Embedding Python, Versión 3.12.0
lambda Una función anónima de una línea consistente en un sola expression que es evaluada cuando la función es llamada.
La sintaxis para crear una función lambda es lambda [parameters]: expression
LBYL Del inglés Look before you leap, «mira antes de saltar». Es un estilo de codificación que prueba explícitamente
las condiciones previas antes de hacer llamadas o búsquedas. Este estilo contrasta con la manera EAFP y está
caracterizado por la presencia de muchas sentencias if.
En entornos multi-hilos, el método LBYL tiene el riesgo de introducir condiciones de carrera entre los hilos
que están «mirando» y los que están «saltando». Por ejemplo, el código, if key in mapping: return
mapping[key] puede fallar si otro hilo remueve key de mapping después del test, pero antes de retornar el
valor. Este problema puede ser resuelto usando bloqueos o empleando el método EAFP.
codificación de la configuración regional On Unix, it is the encoding of the LC_CTYPE locale. It can be set with
locale.setlocale(locale.LC_CTYPE, new_locale).
On Windows, it is the ANSI code page (ex: "cp1252").
On Android and VxWorks, Python uses "utf-8" as the locale encoding.
locale.getencoding() can be used to get the locale encoding.
See also the filesystem encoding and error handler.
lista Es una sequence Python incorporada. A pesar de su nombre es más similar a un arreglo en otros lenguajes que a una
lista enlazada porque el acceso a los elementos es O(1).
comprensión de listas Una forma compacta de procesar todos o parte de los elementos en una secuencia y retornar
una lista como resultado. result = ['{:#04x}'.format(x) for x in range(256) if x % 2
== 0] genera una lista de cadenas conteniendo números hexadecimales (0x..) entre 0 y 255. La cláusula if es
opcional. Si es omitida, todos los elementos en range(256) son procesados.
cargador Un objeto que carga un módulo. Debe definir el método llamado load_module(). Un cargador es nor-
malmente retornados por un finder. Vea PEP 302 para detalles y importlib.abc.Loader para una abstract
base class.
método mágico Una manera informal de llamar a un special method.
mapeado A container object that supports arbitrary key lookups and implements the methods specified in
the collections.abc.Mapping or collections.abc.MutableMapping abstract base clas-
ses. Examples include dict, collections.defaultdict, collections.OrderedDict and
collections.Counter.
meta buscadores de ruta Un finder retornado por una búsqueda de sys.meta_path. Los meta buscadores de ruta
están relacionados a buscadores de entradas de rutas, pero son algo diferente.
Vea en importlib.abc.MetaPathFinder los métodos que los meta buscadores de ruta implementan.
metaclase La clase de una clase. Las definiciones de clases crean nombres de clase, un diccionario de clase, y una lista
de clases base. Las metaclases son responsables de tomar estos tres argumentos y crear la clase. La mayoría de los
objetos de un lenguaje de programación orientado a objetos provienen de una implementación por defecto. Lo que
hace a Python especial que es posible crear metaclases a medida. La mayoría de los usuario nunca necesitarán esta
herramienta, pero cuando la necesidad surge, las metaclases pueden brindar soluciones poderosas y elegantes. Han
sido usadas para loggear acceso de atributos, agregar seguridad a hilos, rastrear la creación de objetos, implementar
singletons, y muchas otras tareas.
Más información hallará en metaclasses.
método Una función que es definida dentro del cuerpo de una clase. Si es llamada como un atributo de una instancia de
otra clase, el método tomará el objeto instanciado como su primer argument (el cual es usualmente denominado
self). Vea function y nested scope.
79
Extending and Embedding Python, Versión 3.12.0
orden de resolución de métodos Orden de resolución de métodos es el orden en el cual una clase base es buscada por
un miembro durante la búsqueda. Mire en The Python 2.3 Method Resolution Order los detalles del algoritmo
usado por el intérprete Python desde la versión 2.3.
módulo Un objeto que sirve como unidad de organización del código Python. Los módulos tienen espacios de nombres
conteniendo objetos Python arbitrarios. Los módulos son cargados en Python por el proceso de importing.
Vea también package.
especificador de módulo Un espacio de nombres que contiene la información relacionada a la importación usada al leer
un módulo. Una instancia de importlib.machinery.ModuleSpec.
MRO Vea method resolution order.
mutable Los objetos mutables pueden cambiar su valor pero mantener su id(). Vea también immutable.
tupla nombrada La denominación «tupla nombrada» se aplica a cualquier tipo o clase que hereda de una tupla y cuyos
elementos indexables son también accesibles usando atributos nombrados. Este tipo o clase puede tener además
otras capacidades.
Varios tipos incorporados son tuplas nombradas, incluyendo los valores retornados por time.localtime() y
os.stat(). Otro ejemplo es sys.float_info:
Algunas tuplas nombradas con tipos incorporados (como en los ejemplo precedentes). También puede ser creada
con una definición regular de clase que hereda de la clase tuple y que define campos nombrados. Una clase
como esta puede ser hechas personalizadamente o puede ser creada con la función factoría collections.
namedtuple(). Esta última técnica automáticamente brinda métodos adicionales que pueden no estar presentes
en las tuplas nombradas personalizadas o incorporadas.
espacio de nombres El lugar donde la variable es almacenada. Los espacios de nombres son implementados como dic-
cionarios. Hay espacio de nombre local, global, e incorporado así como espacios de nombres anidados en objetos
(en métodos). Los espacios de nombres soportan modularidad previniendo conflictos de nombramiento. Por ejem-
plo, las funciones builtins.open y os.open() se distinguen por su espacio de nombres. Los espacios de
nombres también ayuda a la legibilidad y mantenibilidad dejando claro qué módulo implementa una función. Por
ejemplo, escribiendo random.seed() o itertools.islice() queda claro que éstas funciones están im-
plementadas en los módulos random y itertools, respectivamente.
paquete de espacios de nombres Un PEP 420 package que sirve sólo para contener subpaquetes. Los paquetes de es-
pacios de nombres pueden no tener representación física, y específicamente se diferencian de los regular package
porque no tienen un archivo __init__.py.
Vea también module.
alcances anidados La habilidad de referirse a una variable dentro de una definición encerrada. Por ejemplo, una función
definida dentro de otra función puede referir a variables en la función externa. Note que los alcances anidados por
defecto sólo funcionan para referencia y no para asignación. Las variables locales leen y escriben sólo en el alcance
más interno. De manera semejante, las variables globales pueden leer y escribir en el espacio de nombres global.
Con nonlocal se puede escribir en alcances exteriores.
clase de nuevo estilo Vieja denominación usada para el estilo de clases ahora empleado en todos los objetos de clase. En
versiones más tempranas de Python, sólo las nuevas clases podían usar capacidades nuevas y versátiles de Python
como __slots__, descriptores, propiedades, __getattribute__(), métodos de clase y métodos estáticos.
80 Apéndice A. Glosario
Extending and Embedding Python, Versión 3.12.0
objeto Cualquier dato con estado (atributo o valor) y comportamiento definido (métodos). También es la más básica
clase base para cualquier new-style class.
paquete A Python module which can contain submodules or recursively, subpackages. Technically, a package is a Python
module with a __path__ attribute.
Vea también regular package y namespace package.
parámetro Una entidad nombrada en una definición de una function (o método) que especifica un argument (o en algunos
casos, varios argumentos) que la función puede aceptar. Existen cinco tipos de argumentos:
• posicional o nombrado: especifica un argumento que puede ser pasado tanto como posicional o como nom-
brado. Este es el tipo por defecto de parámetro, como foo y bar en el siguiente ejemplo:
• sólo posicional: especifica un argumento que puede ser pasado sólo por posición. Los parámetros sólo po-
sicionales pueden ser definidos incluyendo un carácter / en la lista de parámetros de la función después de
ellos, como posonly1 y posonly2 en el ejemplo que sigue:
• sólo nombrado: especifica un argumento que sólo puede ser pasado por nombre. Los parámetros sólo por
nombre pueden ser definidos incluyendo un parámetro posicional de una sola variable o un simple *` antes
de ellos en la lista de parámetros en la definición de la función, como kw_only1 y kw_only2 en el ejemplo
siguiente:
• variable posicional: especifica una secuencia arbitraria de argumentos posicionales que pueden ser brindados
(además de cualquier argumento posicional aceptado por otros parámetros). Este parámetro puede ser definido
anteponiendo al nombre del parámetro *, como a args en el siguiente ejemplo:
• variable nombrado: especifica que arbitrariamente muchos argumentos nombrados pueden ser brindados
(además de cualquier argumento nombrado ya aceptado por cualquier otro parámetro). Este parámetro pue-
de ser definido anteponiendo al nombre del parámetro con **, como kwargs en el ejemplo precedente.
Los parámetros puede especificar tanto argumentos opcionales como requeridos, así como valores por defecto para
algunos argumentos opcionales.
Vea también el glosario de argument, la pregunta respondida en la diferencia entre argumentos y parámetros, la
clase inspect.Parameter, la sección function , y PEP 362.
entrada de ruta Una ubicación única en el import path que el path based finder consulta para encontrar los módulos a
importar.
buscador de entradas de ruta Un finder retornado por un invocable en sys.path_hooks (esto es, un path entry
hook) que sabe cómo localizar módulos dada una path entry.
Vea en importlib.abc.PathEntryFinder los métodos que los buscadores de entradas de ruta implemen-
tan.
gancho a entrada de ruta Un invocable en la lista sys.path_hook que retorna un path entry finder si éste sabe
cómo encontrar módulos en un path entry específico.
buscador basado en ruta Uno de los meta buscadores de ruta por defecto que busca un import path para los módulos.
objeto tipo ruta Un objeto que representa una ruta del sistema de archivos. Un objeto tipo ruta puede ser tanto una str
como un bytes representando una ruta, o un objeto que implementa el protocolo os.PathLike. Un objeto que
81
Extending and Embedding Python, Versión 3.12.0
soporta el protocolo os.PathLike puede ser convertido a ruta del sistema de archivo de clase str o bytes
usando la función os.fspath(); os.fsdecode() os.fsencode() pueden emplearse para garantizar
que retorne respectivamente str o bytes. Introducido por PEP 519.
PEP Propuesta de mejora de Python, del inglés Python Enhancement Proposal. Un PEP es un documento de diseño que
brinda información a la comunidad Python, o describe una nueva capacidad para Python, sus procesos o entorno.
Los PEPs deberían dar una especificación técnica concisa y una fundamentación para las capacidades propuestas.
Los PEPs tienen como propósito ser los mecanismos primarios para proponer nuevas y mayores capacidad, para
recoger la opinión de la comunidad sobre un tema, y para documentar las decisiones de diseño que se han hecho
en Python. El autor del PEP es el responsable de lograr consenso con la comunidad y documentar las opiniones
disidentes.
Vea PEP 1.
porción Un conjunto de archivos en un único directorio (posiblemente guardo en un archivo comprimido zip) que con-
tribuye a un espacio de nombres de paquete, como está definido en PEP 420.
argumento posicional Vea argument.
API provisional Una API provisoria es aquella que deliberadamente fue excluida de las garantías de compatibilidad
hacia atrás de la biblioteca estándar. Aunque no se esperan cambios fundamentales en dichas interfaces, como están
marcadas como provisionales, los cambios incompatibles hacia atrás (incluso remover la misma interfaz) podrían
ocurrir si los desarrolladores principales lo estiman. Estos cambios no se hacen gratuitamente – solo ocurrirán si
fallas fundamentales y serias son descubiertas que no fueron vistas antes de la inclusión de la API.
Incluso para APIs provisorias, los cambios incompatibles hacia atrás son vistos como una «solución de último
recurso» - se intentará todo para encontrar una solución compatible hacia atrás para los problemas identificados.
Este proceso permite que la biblioteca estándar continúe evolucionando con el tiempo, sin bloquearse por errores
de diseño problemáticos por períodos extensos de tiempo. Vea PEP 411 para más detalles.
paquete provisorio Vea provisional API.
Python 3000 Apodo para la fecha de lanzamiento de Python 3.x (acuñada en un tiempo cuando llegar a la versión 3 era
algo distante en el futuro.) También se lo abrevió como Py3k.
Pythónico Una idea o pieza de código que sigue ajustadamente la convenciones idiomáticas comunes del lenguaje Python,
en vez de implementar código usando conceptos comunes a otros lenguajes. Por ejemplo, una convención común
en Python es hacer bucles sobre todos los elementos de un iterable con la sentencia for. Muchos otros lenguajes
no tienen este tipo de construcción, así que los que no están familiarizados con Python podrían usar contadores
numéricos:
for i in range(len(food)):
print(food[i])
nombre calificado Un nombre con puntos mostrando la ruta desde el alcance global del módulo a la clase, función o
método definido en dicho módulo, como se define en PEP 3155. Para las funciones o clases de más alto nivel, el
nombre calificado es el igual al nombre del objeto:
>>> class C:
... class D:
... def meth(self):
... pass
...
(continué en la próxima página)
82 Apéndice A. Glosario
Extending and Embedding Python, Versión 3.12.0
Cuando es usado para referirse a los módulos, nombre completamente calificado significa la ruta con puntos completo
al módulo, incluyendo cualquier paquete padre, por ejemplo, email.mime.text:
contador de referencias The number of references to an object. When the reference count of an object drops to zero, it
is deallocated. Some objects are «immortal» and have reference counts that are never modified, and therefore the
objects are never deallocated. Reference counting is generally not visible to Python code, but it is a key element of
the CPython implementation. Programmers can call the sys.getrefcount() function to return the reference
count for a particular object.
paquete regular Un package tradicional, como aquellos con un directorio conteniendo el archivo __init__.py.
Vea también namespace package.
__slots__ Es una declaración dentro de una clase que ahorra memoria predeclarando espacio para las atributos de la
instancia y eliminando diccionarios de la instancia. Aunque es popular, esta técnica es algo dificultosa de lograr
correctamente y es mejor reservarla para los casos raros en los que existen grandes cantidades de instancias en
aplicaciones con uso crítico de memoria.
secuencia Un iterable que logra un acceso eficiente a los elementos usando índices enteros a través del método es-
pecial __getitem__() y que define un método __len__() que retorna la longitud de la secuencia. Al-
gunas de las secuencias incorporadas son list, str, tuple, y bytes. Observe que dict también soporta
__getitem__() y __len__(), pero es considerada un mapeo más que una secuencia porque las búsquedas
son por claves arbitraria immutable y no por enteros.
La clase abstracta base collections.abc.Sequence define una interfaz mucho más rica que va más
allá de sólo __getitem__() y __len__(), agregando count(), index(), __contains__(), y
__reversed__(). Los tipos que implementan esta interfaz expandida pueden ser registrados explícitamen-
te usando register().
comprensión de conjuntos Una forma compacta de procesar todos o parte de los elementos en un iterable y retornar
un conjunto con los resultados. results = {c for c in 'abracadabra' if c not in 'abc'}
genera el conjunto de cadenas {'r', 'd'}. Ver comprehensions.
despacho único Una forma de despacho de una generic function donde la implementación es elegida a partir del tipo de
un sólo argumento.
rebanada Un objeto que contiene una porción de una sequence. Una rebanada es creada usando la notación de suscrip-
to, [] con dos puntos entre los números cuando se ponen varios, como en nombre_variable[1:3:5]. La
notación con corchete (suscrito) usa internamente objetos slice.
método especial Un método que es llamado implícitamente por Python cuando ejecuta ciertas operaciones en un tipo,
como la adición. Estos métodos tienen nombres que comienzan y terminan con doble barra baja. Los métodos
especiales están documentados en specialnames.
sentencia Una sentencia es parte de un conjunto (un «bloque» de código). Una sentencia tanto es una expression como
alguna de las varias sintaxis usando una palabra clave, como if, while o for.
83
Extending and Embedding Python, Versión 3.12.0
referencia fuerte In Python’s C API, a strong reference is a reference to an object which is owned by the code holding
the reference. The strong reference is taken by calling Py_INCREF() when the reference is created and released
with Py_DECREF() when the reference is deleted.
La función Py_NewRef() se puede utilizar para crear una referencia fuerte a un objeto. Por lo general, se debe
llamar a la función Py_DECREF() en la referencia fuerte antes de salir del alcance de la referencia fuerte, para
evitar filtrar una referencia.
Consulte también borrowed reference.
codificación de texto A string in Python is a sequence of Unicode code points (in range U+0000–U+10FFFF). To
store or transfer a string, it needs to be serialized as a sequence of bytes.
Serializing a string into a sequence of bytes is known as «encoding», and recreating the string from the sequence
of bytes is known as «decoding».
There are a variety of different text serialization codecs, which are collectively referred to as «text encodings».
archivo de texto Un file object capaz de leer y escribir objetos str. Frecuentemente, un archivo de texto también accede
a un flujo de datos binario y maneja automáticamente el text encoding. Ejemplos de archivos de texto que son abiertos
en modo texto ('r' o 'w'), sys.stdin, sys.stdout, y las instancias de io.StringIO.
Vea también binary file por objeto de archivos capaces de leer y escribir objeto tipo binario.
cadena con triple comilla Una cadena que está enmarcada por tres instancias de comillas (») o apostrofes (“). Aunque
no brindan ninguna funcionalidad que no está disponible usando cadenas con comillas simple, son útiles por varias
razones. Permiten incluir comillas simples o dobles sin escapar dentro de las cadenas y pueden abarcar múltiples
líneas sin el uso de caracteres de continuación, haciéndolas particularmente útiles para escribir docstrings.
tipo El tipo de un objeto Python determina qué tipo de objeto es; cada objeto tiene un tipo. El tipo de un objeto puede
ser accedido por su atributo __class__ o puede ser conseguido usando type(obj).
alias de tipos Un sinónimo para un tipo, creado al asignar un tipo a un identificador.
Los alias de tipos son útiles para simplificar los indicadores de tipo. Por ejemplo:
def remove_gray_shades(
colors: list[tuple[int, int, int]]) -> list[tuple[int, int, int]]:
pass
84 Apéndice A. Glosario
Extending and Embedding Python, Versión 3.12.0
la vieja convención de Macintosh '\r'. Vea PEP 278 y PEP 3116, además de bytes.splitlines() para
usos adicionales.
anotación de variable Una annotation de una variable o un atributo de clase.
Cuando se anota una variable o un atributo de clase, la asignación es opcional:
class C:
field: 'annotation'
Las anotaciones de variables son frecuentemente usadas para type hints: por ejemplo, se espera que esta variable
tenga valores de clase int:
count: int = 0
85
Extending and Embedding Python, Versión 3.12.0
86 Apéndice A. Glosario
APÉNDICE B
Estos documentos son generados por reStructuredText desarrollado por Sphinx, un procesador de documentos específi-
camente escrito para la documentación de Python.
El desarrollo de la documentación y su cadena de herramientas es un esfuerzo enteramente voluntario, al igual que Python.
Si tu quieres contribuir, por favor revisa la página reporting-bugs para más información de cómo hacerlo. Los nuevos
voluntarios son siempre bienvenidos!
Agradecemos a:
• Fred L. Drake, Jr., el creador original de la documentación del conjunto de herramientas de Python y escritor de
gran parte del contenido;
• the Docutils project for creating reStructuredText and the Docutils suite;
• Fredrik Lundh for his Alternative Python Reference project from which Sphinx got many good ideas.
Muchas personas han contribuido para el lenguaje de Python, la librería estándar de Python, y la documentación de
Python. Revisa Misc/ACKS la distribución de Python para una lista parcial de contribuidores.
Es solamente con la aportación y contribuciones de la comunidad de Python que Python tiene tan fantástica documentación
– Muchas gracias!
87
Extending and Embedding Python, Versión 3.12.0
Historia y Licencia
Python fue creado a principios de la década de 1990 por Guido van Rossum en Stichting Mathematisch Centrum (CWI,
ver https://www.cwi.nl/) en los Países Bajos como sucesor de un idioma llamado ABC. Guido sigue siendo el autor
principal de Python, aunque incluye muchas contribuciones de otros.
En 1995, Guido continuó su trabajo en Python en la Corporation for National Research Initiatives (CNRI, consulte https:
//www.cnri.reston.va.us/) en Reston, Virginia, donde lanzó varias versiones del software.
En mayo de 2000, Guido y el equipo de desarrollo central de Python se trasladaron a BeOpen.com para formar el equipo
de BeOpen PythonLabs. En octubre del mismo año, el equipo de PythonLabs se trasladó a Digital Creations (ahora Zope
Corporation; consulte https://www.zope.org/). En 2001, se formó la Python Software Foundation (PSF, consulte https:
//www.python.org/psf/), una organización sin fines de lucro creada específicamente para poseer la propiedad intelectual
relacionada con Python. Zope Corporation es miembro patrocinador del PSF.
Todas las versiones de Python son de código abierto (consulte https://opensource.org/ para conocer la definición de código
abierto). Históricamente, la mayoría de las versiones de Python, pero no todas, también han sido compatibles con GPL;
la siguiente tabla resume las distintas versiones.
89
Extending and Embedding Python, Versión 3.12.0
Nota: Compatible con GPL no significa que estemos distribuyendo Python bajo la GPL. Todas las licencias de Python,
a diferencia de la GPL, le permiten distribuir una versión modificada sin que los cambios sean de código abierto. Las
licencias compatibles con GPL permiten combinar Python con otro software que se publica bajo la GPL; los otros no lo
hacen.
Gracias a los muchos voluntarios externos que han trabajado bajo la dirección de Guido para hacer posibles estos lanza-
mientos.
2. Subject to the terms and conditions of this License Agreement, PSF hereby
grants Licensee a nonexclusive, royalty-free, world-wide license to␣
,→reproduce,
agrees to include in any such work a brief summary of the changes made to␣
,→Python
3.12.0.
5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 3.12.0
FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT␣
,→OF
Agreement does not grant permission to use PSF trademarks or trade name in␣
,→a
third party.
2. Subject to the terms and conditions of this BeOpen Python License Agreement,
BeOpen hereby grants Licensee a non-exclusive, royalty-free, world-wide license
to reproduce, analyze, test, perform and/or display publicly, prepare derivative
works, distribute, and otherwise use the Software alone or in any derivative
version, provided, however, that the BeOpen Python License is retained in the
Software, alone or in any derivative version prepared by Licensee.
4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE SOFTWARE FOR
ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF USING,
MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY DERIVATIVE THEREOF, EVEN IF
ADVISED OF THE POSSIBILITY THEREOF.
(continué en la próxima página)
2. Subject to the terms and conditions of this License Agreement, CNRI hereby
grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
analyze, test, perform and/or display publicly, prepare derivative works,
distribute, and otherwise use Python 1.6.1 alone or in any derivative version,
provided, however, that CNRI's License Agreement and CNRI's notice of copyright,
i.e., "Copyright © 1995-2001 Corporation for National Research Initiatives; All
Rights Reserved" are retained in Python 1.6.1 alone or in any derivative version
prepared by Licensee. Alternately, in lieu of CNRI's License Agreement,
Licensee may substitute the following text (omitting the quotes): "Python 1.6.1
is made available subject to the terms and conditions in CNRI's License
Agreement. This Agreement together with Python 1.6.1 may be located on the
internet using the following unique, persistent identifier (known as a handle):
1895.22/1013. This Agreement may also be obtained from a proxy server on the
internet using the following URL: http://hdl.handle.net/1895.22/1013."
4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" basis. CNRI
MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE,
BUT NOT LIMITATION, CNRI MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY
OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF
PYTHON 1.6.1 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 1.6.1 FOR
ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF
MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, OR ANY DERIVATIVE
(continué en la próxima página)
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided that
the above copyright notice appear in all copies and that both that copyright
notice and this permission notice appear in supporting documentation, and that
the name of Stichting Mathematisch Centrum or CWI not be used in advertising or
publicity pertaining to distribution of the software without specific, written
prior permission.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
Esta sección es una lista incompleta, pero creciente, de licencias y reconocimientos para software de terceros incorporado
en la distribución de Python.
The _random C extension underlying the random module includes code based on a download from http://www.math.
sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html. The following are the verbatim comments from the ori-
ginal code:
A C-program for MT19937, with initialization improved 2002/1/26.
Coded by Takuji Nishimura and Makoto Matsumoto.
C.3.2 Sockets
The socket module uses the functions, getaddrinfo(), and getnameinfo(), which are coded in separate
source files from the WIDE Project, https://www.wide.ad.jp/.
THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
Permission to use, copy, modify, and distribute this Python software and
its associated documentation for any purpose without fee is hereby
granted, provided that the above copyright notice appears in all copies,
and that both that copyright notice and this permission notice appear in
supporting documentation, and that the name of neither Automatrix,
Bioreason or Mojam Media be used in advertising or publicity pertaining to
distribution of the software without specific, written prior permission.
SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
OF THIS SOFTWARE.
C.3.8 test_epoll
Copyright (c) 2000 Doug White, 2006 James Knight, 2007 Christian Heimes
All rights reserved.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
C.3.10 SipHash24
El archivo Python/pyhash.c contiene la implementación de Marek Majkowski del algoritmo SipHash24 de Dan
Bernstein. Contiene la siguiente nota:
<MIT License>
Copyright (c) 2013 Marek Majkowski <[email protected]>
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
</MIT License>
The file Python/dtoa.c, which supplies C functions dtoa and strtod for conversion of C doubles to and from strings,
is derived from the file of the same name by David M. Gay, currently available from https://web.archive.org/web/
20220517033456/http://www.netlib.org/fp/dtoa.c. The original file, as retrieved on March 16, 2009, contains the fo-
llowing copyright and licensing notice:
/****************************************************************
*
* The author of this software is David M. Gay.
*
* Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
*
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*
***************************************************************/
C.3.12 OpenSSL
The modules hashlib, posix, ssl, crypt use the OpenSSL library for added performance if made available by
the operating system. Additionally, the Windows and macOS installers for Python may include a copy of the OpenSSL
libraries, so we include a copy of the OpenSSL license here. For the OpenSSL 3.0 release, and later releases derived from
that, the Apache License v2 applies:
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
(continué en la próxima página)
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
C.3.13 expat
The pyexpat extension is built using an included copy of the expat sources unless the build is configured
--with-system-expat:
Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
and Clark Cooper
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
C.3.14 libffi
The _ctypes C extension underlying the ctypes module is built using an included copy of the libffi sources unless
the build is configured --with-system-libffi:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
C.3.15 zlib
La extensión zlib se crea utilizando una copia incluida de las fuentes de zlib si la versión de zlib encontrada en el sistema
es demasiado antigua para ser utilizada para la compilación:
Copyright (C) 1995-2011 Jean-loup Gailly and Mark Adler
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
C.3.16 cfuhash
C.3.17 libmpdec
The _decimal C extension underlying the decimal module is built using an included copy of the libmpdec library
unless the build is configured --with-system-libmpdec:
Copyright (c) 2008-2020 Stefan Krah. All rights reserved.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
El conjunto de pruebas C14N 2.0 en el paquete test (Lib/test/xmltestdata/c14n-20/) se recuperó del sitio
web de W3C en https://www.w3.org/TR/xml-c14n2-testcases/ y se distribuye bajo la licencia BSD de 3 cláusulas:
Copyright (c) 2013 W3C(R) (MIT, ERCIM, Keio, Beihang),
All Rights Reserved.
C.3.19 Audioop
The audioop module uses the code base in g771.c file of the SoX project:
Derechos de autor
Consulte Historia y Licencia para obtener información completa sobre licencias y permisos.
109
Extending and Embedding Python, Versión 3.12.0
No alfabético cargador, 79
..., 71 C-contiguous, 74
2to3, 71 clase, 73
>>>, 71 clase base abstracta, 71
__future__, 76 clase de nuevo estilo, 80
__slots__, 83 codificación de la configuración
regional, 79
A codificación de texto, 84
a la espera, 72 codificación del sistema de archivos y
administrador asincrónico de contexto, manejador de errores, 75
72 comprensión de conjuntos, 83
administrador de contextos, 74 comprensión de diccionarios, 74
alcances anidados, 80 comprensión de listas, 79
alias de tipos, 84 contador de referencias, 83
anotación, 71 contiguo, 74
anotación de función, 76 corrutina, 74
anotación de variable, 85 CPython, 74
apagado del intérprete, 78
API provisional, 82 D
archivo binario, 73 deallocation, object, 51
archivo de texto, 84 decorador, 74
argumento, 71 descriptor, 74
argumento nombrado, 78 despacho único, 83
argumento posicional, 82 diccionario, 74
atributo, 72 división entera, 76
docstring, 75
B
BDFL, 73 E
bloqueo global del intérprete, 77 EAFP, 75
built-in function entorno virtual, 85
repr, 52 entrada de ruta, 81
buscador, 76 espacio de nombres, 80
buscador basado en ruta, 81 especificador de módulo, 80
buscador de entradas de ruta, 81 expresión, 75
bytecode, 73 expresión generadora, 76
C F
cadena con triple comilla, 84 f-string, 75
callable, 73 finalization, of objects, 51
111
Extending and Embedding Python, Versión 3.12.0
Fortran contiguous, 74 N
función, 76 nombre calificado, 82
función clave, 78 número complejo, 73
función corrutina, 74
función genérica, 77 O
object
G deallocation, 51
gancho a entrada de ruta, 81 finalization, 51
generador, 76 objeto, 81
generador asincrónico, 72 objeto archivo, 75
GIL, 77 objeto tipo ruta, 81
objetos tipo archivo, 75
H objetos tipo binarios, 73
hash-based pyc, 77 orden de resolución de métodos, 80
hashable, 77
P
I paquete, 81
IDLE, 77 paquete de espacios de nombres, 80
importador, 77 paquete provisorio, 82
importar, 77 paquete regular, 83
indicador de tipo, 84 parámetro, 81
inmutable, 77 PEP, 82
interactivo, 77 Philbrick, Geoff, 16
interpretado, 78 porción, 82
iterable, 78 PyArg_ParseTuple(), 14
iterable asincrónico, 72 PyArg_ParseTupleAndKeywords(), 16
iterador, 78 PyErr_Fetch(), 52
iterador asincrónico, 72 PyErr_Restore(), 52
iterador generador, 76 PyInit_modulename (C function), 59
iterador generador asincrónico, 72 PyObject_CallObject(), 13
Python 3000, 82
L Python Enhancement Proposals
lambda, 79 PEP 1, 82
LBYL, 79 PEP 238, 76
lista, 79 PEP 278, 85
PEP 302, 76, 79
M PEP 343, 74
magic PEP 362, 72, 81
método, 79 PEP 411, 82
mapeado, 79 PEP 420, 76, 80, 82
máquina virtual, 85 PEP 442, 52
meta buscadores de ruta, 79 PEP 443, 77
metaclase, 79 PEP 451, 76
método, 79 PEP 483, 77
magic, 79 PEP 484, 71, 76, 77, 84, 85
special, 83 PEP 489, 11, 59
método especial, 83 PEP 492, 72, 74
método mágico, 79 PEP 498, 75
módulo, 80 PEP 519, 82
módulo de extensión, 75 PEP 525, 72
MRO, 80 PEP 526, 71, 85
mutable, 80 PEP 585, 77
PEP 3116, 85
PEP 3155, 82
112 Índice
Extending and Embedding Python, Versión 3.12.0
Pythónico, 82
PYTHONPATH, 59
R
rebanada, 83
recolección de basura, 76
referencia fuerte, 84
referencia prestada, 73
repr
built-in function, 52
retrollamada, 73
ruta de importación, 77
S
saltos de líneas universales, 84
secuencia, 83
sentencia, 83
special
método, 83
string
object representation, 52
T
tipado de pato, 75
tipo, 84
tipos genéricos, 77
tupla nombrada, 80
V
variable de clase, 73
variable de contexto, 74
variables de entorno
PYTHONPATH, 59
vista de diccionario, 75
Z
Zen de Python, 85
Índice 113