Beruflich Dokumente
Kultur Dokumente
Python
Versión 2.0
16 de octubre de 2000
BeOpen PythonLabs
Correo electrónico: python-docs@python.org
BEOPEN.COM TERMS AND CONDITIONS FOR PYTHON 2.0
BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
1. This LICENSE AGREEMENT is between BeOpen.com (“BeOpen”), having an office at 160 Saratoga Avenue,
Santa Clara, CA 95051, and the Individual or Organization (“Licensee”) accessing and otherwise using this
software in source or binary form and its associated documentation (“the Software”).
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.
3. BeOpen is making the Software available to Licensee on an “AS IS” basis. BEOPEN MAKES NO REPRESEN-
TATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION,
BEOPEN MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTA-
BILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE
WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.
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 ADVI-
SED OF THE POSSIBILITY THEREOF.
5. This License Agreement will automatically terminate upon a material breach of its terms and conditions.
6. This License Agreement shall be governed by and interpreted in all respects by the law of the State of Cali-
fornia, excluding conflict of law provisions. Nothing in this License Agreement shall be deemed to create any
relationship of agency, partnership, or joint venture between BeOpen and Licensee. This License Agreement
does not grant permission to use BeOpen trademarks or trade names in a trademark sense to endorse or promote
products or services of Licensee, or any third party. As an exception, the “BeOpen Python” logos available at
http://www.pythonlabs.com/logos.html may be used according to the permissions granted on that web page.
7. By copying, installing or otherwise using the software, Licensee agrees to be bound by the terms and conditions
of this License Agreement.
Python es un lenguaje de programación interpretado y orientado a objetos. Este documento describe cómo escribir
módulos en C o C++ para extender el intérprete de Python con nuevos módulos. Estos módulos pueden definir nuevas
funciones y también nuevos tipos de objetos con sus métodos. También se describe cómo empotrar el intérprete de
python en otra aplicación, para usarlo como lenguaje de extensión (como los lenguajes de macro). Al final, explica
cómo compilar y enlazar los módulos de extensión para que se carguen dinámicamente (en tiempo de ejecución) en el
intérprete, siempre que el sistema operativo tenga esta posibilidad.
Este documento supone un conocimiento básico de Python. Hay una introducción informal al lenguaje en la Guía de
aprendizaje de Python. El Manual de referencia de Python proporciona una definición más formal del lenguaje. La
Referencia de la biblioteca de Python documenta los tipos de objetos existentes, funciones y módulos (tanto internos
como escritos en Python) que dan al lenguaje su amplio rango de aplicación.
Si se desea una descripción detallada del API de Python/C, se debe consultar el Manual de referencia del API Python/C.
ÍNDICE GENERAL
A Informes de error 35
i
ii
CAPÍTULO
UNO
Es bastante fácil añadir nuevos módulos internos a Python si se sabe programar en C. Tales módulos de extensión
pueden hacer cosas que no se pueden hacer directamente en Python: implementan nuevos tipos de objetos internos y
son capaces de llamara a funciones de C y hacer llamadas al sistema.
Para dar soporte a las extensiones, el API (Interfaz de aplicación para programadores) de Python define un conjunto
de funciones, macros y variables que proporcionan acceso a la mayoría de los aspectos del sistema de ejecución de
Python. El API de Python se incorpora en un fichero fuente C incluyendo la cabecera "Python.h".
La compilación de un módulo de extensión depende de su futuro uso y de la configuración del sistema, sobre lo que
se habla en capítulos posteriores.
Se empieza por crear un fichero ‘spammodule.c’. Por tradición, si un módulo se llama ‘spam’, el fichero C que
contiene su implementación se llama ‘spammodule.c’. Si el nombre del módulo es largo, como ‘spammify’, el
módulo se puede llamar sólo ‘spammify.c’.
La primera línea del fichero será:
#include <Python.h>
Lo que pone disponible el API de Python (se puede añadir comentarios que describan el propósito del módulo y una
nota de derechos de copia).
Todos los símbolos visibles por el usuario definidos por "Python.h" tienen un prefijo ‘Py’ o ‘PY’, excepto aquéllos
definidos en ficheros de cabeceras estándar. Por comodidad y, ya que se utilizan extensivamente en el intérprete de
Python, "Python.h" incluye unos cuantos ficheros de cabecera: <stdio.h>, <string.h>, <errno.h> y
1 N. del T.: “Spam” se puede traducir como magro. Aparece tanto en ejemplos, etc. que me ha parecido mejor dejarlo tal cual, lo que además
1
<stdlib.h>. Si en el sistema no existe este último fichero, se declaran las funciones malloc(), free() y
realloc() directamente.
Lo siguiente que se añade al módulo de extensión es la función C que se invocará al evaluar la expresión de Python
‘spam.system(string)’ (pronto se verá como se acaba invocando):
static PyObject *
spam_system(self, args)
PyObject *self;
PyObject *args;
{
char *orden;
int sts;
Hay una traducción directa desde la lista de argumentos de Python (es decir, la expresión simple "ls -l") a los
argumentos que se pasan a la función de C. La función de C siempre tiene dos argumentos, por convención self y args.
El argumento self sólo se utiliza cuando la función C implementa un método interno, no una función. En el ejemplo,
self siempre será un puntero NULL, porque se está definiendo una función y no un método (se hace así para que el
intérprete no se tenga que entender con dos tipos diferentes de funciones C).
El argumento args será un puntero a un objeto 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, por lo que
para hacer cualquier cosa útil con ellos habrá que convertirlos a valores de C. La función PyArg_ParseTuple()
del API de Python comprueba los tipos de argumento y los convierte a valores de C. Usa una cadena de plantilla para
determinar los tipos de los argumentos y los tipos C de las variables en las que almacenar los valores convertidos. Ya
se hablará de esto más tarde.
PyArg_ParseTuple() devuelve verdadero (no cero) si todos los argumentos son del tipo correcto y sus compo-
nentes han sido almacenados en las variables cuyas direcciones se pasaron. Devuelve falso (cero) si se pasa una lista
de argumentos incorrecta. En este caso, también lanza una excepción adecuada, por lo que la función llamante debe
devolver NULL de inmediato (como se vio en el ejemplo).
y se inicializa en la función de inicialización del módulo (initspam()) con un objeto excepción, por ejemplo, y
dejando aparte la comprobación de errores de momento:
m = Py_InitModule("spam", SpamMethods);
d = PyModule_GetDict(m);
SpamError = PyErr_NewException("spam.error", NULL, NULL);
PyDict_SetItemString(d, "error", SpamError);
}
Es importante hacer ver que el nombre en Python del objeto excepción es spam.error. La función
PyErr_NewException() puede crear tanto una cadena como una clase, dependiendo de si se pasó el indica-
dor -X al intérprete. Si se puso -X, SpamError será un objeto cadena; en caso contrario será un objeto de clase cuya
clase base será Exception, descrita en la Referecia de la biblioteca de Python en “Excepciones internas”.
Devuelve NULL (el indicador de error de las funciones que devuelven punteros a objetos) si se detecta un error en la
lista de argumentos, delegando en la excepción establecida por PyArg_ParseTuple(). En caso contrario, el valor
de cadena del argumento se copia a la variable local orden. Se trata de una asignación de punteros, se supone que
no se debe modificar la cadena a la que apunta (por lo que en C estándar, se debería declarar la variable orden como
‘const char *orden’).
La sentencia siguiente es una llamada a la función de U NIX system(), pasándole la cadena que acabamos de obtener
de PyArg_ParseTuple():
sts = system(orden);
Nuestra función spam.system() debe devolver el valor de sts como objeto de Python. Esto se logra utilizando
la función Py_BuildValue(), que es de algún modo la inversa de PyArg_ParseTuple(): toma una cadena de
formato y un número arbitrario de valores C y devuelve un nuevo objeto Python. Se proporcionará más información
acerca de Py_BuildValue() más tarde.
En este caso, devolverá un objeto entero (¡sí, hasta los enteros son objetos en el montículo (heap) en Python!).
Si se trata de una función C que no devuelve un argumento útil (una función que devuelve void), la función corres-
pondiente en Python debe devolver None. Por convención, se utiliza:
Py_INCREF(Py_None);
return Py_None;
void
initspam()
{
(void) Py_InitModule("spam", SpamMethods);
}
spam spammodule.o
y reconstruir el intérprete ejecutando make en el directorio base. También se puede ejecutar make en el subdirectorio
de ‘Modules/’, pero entonces hay que reconstruir primero el ‘Makefile’ ejecutando ‘make Makefile’ (es necesario cada
vez que se cambia el fichero ‘Setup’).
Si el módulo utiliza más bibliotecas de enlace, se pueden enumerara en la línea correspondiente del fichero de confi-
guración, por ejemplo:
static PyObject *
my_set_callback(dummy, args)
PyObject *dummy, *args;
{
PyObject *result = NULL;
PyObject *temp;
Esta función debe estar registrada en el intérprete mediante el indicador METH_VARARGS, lo que se describe en la
sección 1.4, “La tabla de métodos y la función de inicialización del módulo ”. La función PyArg_ParseTuple()
y sus argumentos están documentados en la sección 1.7 “Cadenas de formato de PyArg_ParseTuple()”.
Las macros Py_XINCREF() y Py_XDECREF() incrementan/decrementan el saldo de referencias de un objeto y son
seguras en la presencia de punteros NULL (obsérvese que temp no será NULL en este contexto). Hay más información
en la sección 1.10, “Saldos de referencias.”
Más tarde cuando toque evaluar la función, se debe llamar a la función C PyEval_CallObject(). Esta función
toma dos argumentos, los dos punteros a objetos de Python arbitrarios: la función Python y la lista de argumentos.
La lista de argumentos siempre debe ser un objeto tupla cuya longitud sea el número de argumentos. Para llamar a la
función de Python si argumentos, se debe pasar una tupla vacía. Para pasar un solo argumento, se debe pasar una tupla
de un solo elemento. Py_BuildValue() devuelve una tupla cuando su cadena de formato consta de cero o más
códigos de formato entre paréntesis. Por ejemplo:
PyEval_CallObject() devuelve un puntero a objeto Python: el valor devuelto por la función de Python. PyE-
val_CallObject() es neutro respecto al saldo de referencias de sus argumentos. En el ejemplo, se crea una nueva
tupla para servir de lista de argumentos, que sufre una llamada a Py_DECREF() inmediatamente tras la llamada.
El valor devuelto por PyEval_CallObject() es “nuevo”: bien es un objeto completamente nuevo o es un objeto
existente cuyo saldo de referencias se ha incrementado. Por ello, salvo que se vaya a guardar el objeto en una variable
global, se debe someter el resultado a Py_DECREF(), incluso (¡más aún!) si no se está interesado en el valor.
Antes de hacerlo, sin embargo, es importante comprobar que el valor no es NULL. De serlo, la función termino su eje-
cución con una excepción. Si el código C que llamó a PyEval_CallObject() fue llamado desde Python, debería
devolver una indicación de error a su llamante Python, para que el intérprete sea capaz de presentar la información
de la excepción o el código Python sea capaz de gestionar la excepción. Si esto no es posible o conveniente, debería
limpiarse la excepción llamando a PyErr_Clear(). Por ejemplo:
if (result == NULL)
return NULL; /* Remitir el error */
...use result...
Py_DECREF(result);
Dependiendo de la interfaz con la función de respuesta de Python deseada, puede que se tenga que proporcionar una
lista de argumentos para PyEval_CallObject(). En ciertos casos, también el programa en Python proporciona
la lista de argumentos, a través de la misma interfaz especificada por la función de respuesta. Así, puede guardarse y
utilizarse del mismo modo que el objeto función. En otros casos, puede que haya que construir una nueva tupla para
pasar la lista de argumentos.El modo más sencillo de hacerlo es llamar a Py_BuildValue(). Por ejemplo, si se
desea pasar un código de suceso entero, puede usarse el siguiente código:
PyObject *arglist;
...
arglist = Py_BuildValue("(l)", eventcode);
result = PyEval_CallObject(my_callback, arglist);
Py_DECREF(arglist);
if (result == NULL)
return NULL; /* Devolver el error */
/* Aquí se puede usar el resultado */
Py_DECREF(result);
El argumento arg debe ser un objeto 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 más adelante. El resto de los argumentos
deben ser direcciones de variables cuyo tipo queda determinado por la cadena de formato. Para que tenga éxito la
conversión, el objeto arg debe concordar con el formato y utilizarlo por completo.
Aunque PyArg_ParseTuple() comprueba que los argumentos de Python tienen los tipos indicados, no puede
comprobar la validez de las direcciones de las variables de C que se pasen a la llamada: si se cometen errores en este
punto, el código efectuará operaciones no válidas o, al menos, sobreescribirá porciones aleatorias de la memoria. ¡Hay
que tener cuidado!
Una cadena de formato consta de cero o más “unidades de formato”. Una unidad de formato describe un objeto
Python. Suele ser un solo carácter o una secuencia de unidades de formato entre paréntesis. Salvo algunas excepciones,
una unidad de formato que no es una secuencia entre paréntesis corresponde a un solo argumento de dirección para
PyArg_ParseTuple(). En la siguiente descripción, la forma entrecomillada es la unidad de formato, la entrada
entre paréntesis es el tipo de objeto Python que concuerda con la unidad de formato y la entrada entre corchetes es el
tipo de la/s variable/s C cuyas direcciones se han de pasar (se debe usar el operador ‘&’ para pasar la dirección de una
variable).
Todas las referencias a objetos de Python proporcionadas al llamante son referencias prestadas; no se debe decrementar
su saldo de referencias.
‘s’ (cadena u objeto Unicode) [char *] Convierte una cadena u objeto Unicode de Python a puntero a cadena de
caracteres de C. No hay que proporcionar almacenamiento a la propia cadena, ya que se guarda un puntero a una
cadena existente en la variable puntero a carácter cuya dirección se pasa. La cadena C está terminada por nulo.
La cadena de Python no debe contener bytes nulos, en caso contrario, se lanza una excepción TypeError. Los
objetos Unicode se convierten a cadenas de C utilizando la codificación predeterminada. Si falla la conversión,
se lanza una excepción UnicodeError.
‘s#’ (objeto cadena, Unicode o cualquier objeto legible con read) [char *, int] Esta variación sobre ‘s’ almace-
na en dos variables de C, la primera un puntero a una cadena de caracteres y la segunda su longitud. En este
caso, la cadena Python puede contener bytes cero en medio. Los objetos Unicode devuelven un puntero a la
versión codificada por defecto de la cadena si tal conversión es posible. Los demás objetos legibles devuelven
una referencia a la representación de los datos internos en crudo.
‘z’ (cadena o None) [char *] Como ‘s’, pero el objeto Python puede ser también None, en cuyo caso el puntero C
se pone a NULL.
‘z#’ (cadena o None o cualquier objeto legible con read) [char *, int] Esto es a ‘s#’ lo que ‘z’ es a ‘s’.
‘u’ (objeto Unicode) [Py_UNICODE *] Convierte un objeto Unicode de Python a un puntero C que apunta a una
cadena terminada en nulo de datos Unicode (UTF-16). Como con ‘s’, no es necesario proporcionar espacio
para la cadena de datos Unicode, se guarda un puntero a los datos Unicode existentes en la variable puntero
Py_UNICODE cuya dirección se pasa.
‘u#’ (objeto Unicode) [Py_UNICODE *, int] Esta variación sobre ‘u’ almacena en dos variables de C, la primera
un puntero a una cadena de datos Unicode y la segunda su longitud.
‘es’ (objeto cadena, Unicode o cualquier objeto legible con read) [const char *encoding, char **buffer] Esta
variación sobre ‘s’ se usa para codificar objetos Unicode y objetos convertibles en Unicode en una cadena de
caracteres. Sólo funciona para datos codificados sin caracteres NULL en medio.
‘D’ (complex) [Py_complex] Convierte un número complejo de Python a una estructura Py_complex de C.
‘O’ (objeto) [PyObject *] Almacena un objeto de Python (sin conversión ninguna) a un puntero a objeto de C. El
programa de C recibe el objeto real traspasado. No se incrementa el saldo de referencias del puntero. El puntero
almacenado no es NULL.
‘O!’ (objeto) [typeobject, PyObject *] Almacena un objeto de Python en un puntero a objeto de C. Se parece a ‘O’,
pero toma dos argumentos: el primero es la dirección de un objeto tipo de Python, el segundo es la dirección de
la variable C (de tipo PyObject *) en la que se almacena el puntero a objeto. Si el objeto de Python no tiene
el tipo exigido, se lanza TypeError.
Es posible pasar enteros largos de Python cuando se requieran enteros. Sin embargo, no se hace una verificación de
rangos, truncándose los bits más significativos silenciosamente si el campo receptor es demasiado pequeño para recibir
el valor (en realidad, la semántica se hereda de las conversiones de C, por lo que puede ocurrir cualquier cosa).
Hay otros caracteres que tienen significado dentro de una cadena de formato. No pueden darse dentro de paréntesis
anidados. Son:
‘|’ Indica que el resto de los argumentos de la lista de argumentos de Python es opcional. Las variable de C corres-
pondientes a los argumentos opcionales deberían inicializarse a su valor por omisión. Cuando no se da valor a
un argumento opcional, PyArg_ParseTuple() no toca el contenido de las variables C correspondientes.
‘:’ La lista de unidades de formato termina aquí: la cadena que sigue a los dos puntos se utiliza como nombre de la
función en mensajes de error (el “valor asociado” de la excepción que lanza PyArg_ParseTuple()).
‘;’ La lista de unidades de formato termina aquí: la cadena que sigue a los dos puntos se usa como mensaje de error
en lugar del mensaje de error predeterminado. Obviamente, ‘:’ y ‘;’ son mutuamente excluyentes.
Llamadas de ejemplo:
vale = PyArg_ParseTuple(args, "lls", &k, &l, &s); /* Dos enteros y una cadena */
/* Posible llamada desde Python: f(1, 2, ’tres’) */
{
char *fichero;
char *modo = "r";
int tamanhobloque = 0;
ok = PyArg_ParseTuple(args, "s|si", &fichero, &modo, &tamanhobloque);
/* Una cadena y, opcionalmente, otra cadena y un entero */
/* Posibles llamadas desde Python:
f(’spam’)
f(’spam’, ’w’)
f(’spam’, ’wb’, 100000) */
}
{
int izquierda, tope, derecha, base, h, v;
ok = PyArg_ParseTuple(args, "((ii)(ii))(ii)",
&izquierda, &tope, &derecha, &base, &h, &v);
/* Un rectángulo y un punto */
/* Posible llamada desde Python:
f(((0, 0), (400, 300)), (10, 10)) */
}
{
Py_complex c;
ok = PyArg_ParseTuple(args, "D:mifuncion", &c);
/* un complejo, más un nombre de función para los errores */
/* Posible llamada desde Python: mifuncion(1+2j) */
}
Los parámetros arg y format son idénticos a los de la función PyArg_ParseTuple(). El parámetro kwdict es un
diccionario de claves recibidas como tercer parámetro del entorno 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 casan con la información de tipos
de format de izquierda a derecha.
Nota: No es posible analizar tuplas anidadas si se usan argumentos clave. Los parámetros clave no presentes en kwlist
lanzarán TypeError.
He aquí un módulo de ejemplo que toma parámetros clave, basado en un ejemplo de Geoff Philbrick
(philbrick@hks.com):
static PyObject *
argsclave_loro(self, args, keywds)
PyObject *self;
PyObject *args;
PyObject *keywds;
{
int tension;
char *estado= "un fiambre";
char *accion = "despegaría";
char *tipo = "Azul noruego";
Py_INCREF(Py_None);
return Py_None;
}
void
initargsclave()
{
/* Crear el módulo y añadir las funciones */
Py_InitModule("argsclave", metodos_argsclave);
}
Reconoce un conjunto de unidades de formato similares a las reconocidas por PyArg_ParseTuple(), pero los
argumentos (que son entradas a la función y no salidas) no deben ser punteros, sino simples valores. Devuelve un
objeto Python nuevo, susceptible de ser devuelto por una función C invocada desde Python.
Una diferencia con PyArg_ParseTuple(): mientras ésta exige que su primer argumento sea una tupla (ya que
las listas de argumentos en Python siempre se representan mediante tuplas internamente), Py_BuildValue() no
‘s’ (string) [char *] Convierte una cadena C terminada en nulo a un objeto Python. Si la cadena C es NULL, se
devuelve None.
‘s#’ (string) [char *, int] Convierte una cadena C y su longitud a un objeto Python. Si la cadena C es NULL, se usa
None, haciendo caso omiso de la longitud.
‘z’ (cadena o None) [char *] Como ‘s’.
‘z#’ (cadena o None) [char *, int] Como ‘s#’.
‘u’ (cadena Unicode) [Py_UNICODE *] Convierte un bloque de datos Unicode (UCS-2) terminado en nulo a un
objeto Unicode de Python. Si el puntero al bloque es NULL, se devuelve None.
‘u#’ (cadena Unicode) [Py_UNICODE *, int] Convierte un bloque de datos Unicode (UCS-2) y su longitud a un
objeto Unicode de Python. Si el puntero al bloque es NULL, se devuelve None, haciendo caso omiso de la
longitud.
‘i’ (entero) [int] Convierte un int de C a un objeto entero de Python.
‘b’ (entero) [char] Como ‘i’.
‘h’ (entero) [short int] Como ‘i’.
‘l’ (entero) [long int] Convierte un long int de C a un objeto entero de Python.
‘c’ (cadena de longitud 1) [char] Convierte un int que representa un carácter a una cadena de Python de longitud
1.
‘d’ (float) [double] Convierte un double de C a un número en coma flotante de Python.
‘f’ (float) [float] Como ‘d’.
‘O’ (objeto) [PyObject *] Pasa un objeto Python intacto (salvo su saldo de referencias, incrementado en uno). Si el
objeto es un puntero NULL, se asume que la causa es que la llamada que obtuvo el argumento encontró un error
y activó una excepción. Por ello, Py_BuildValue() devolverá NULL pero no lanzará una excepción. Si no
hay una excepción activa, se activa PyExc_SystemError.
‘S’ (objeto) [PyObject *] Como ‘O’.
Py_BuildValue("") None
Py_BuildValue("i", 123) 123
Py_BuildValue("iii", 123, 456, 789) (123, 456, 789)
Py_BuildValue("s", "hola") ’hola’
Py_BuildValue("ss", "hola", "mundo") (’hola’, ’mundo’)
Py_BuildValue("s#", "hola", 3) ’hol’
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 gestionan el incremento y decremento del saldo de re-
ferencias. Py_DECREF() también libera el objeto cuando el saldo llega a cero. Para ser más flexible, no llama a
free() directamente, sino que realiza una llamada mediante un puntero a función del tipo de objeto del objeto. Por
esto y otros motivos, cada objeto también contiene un puntero a su tipo de objeto.
Queda la gran cuestión: cuándo usar Py_INCREF(x) y Py_DECREF(x). Vamos a presentar algunos términos.
Nadie “posee” un objeto, pero puede poseer una referencia al objeto. El saldo de referencias del objeto se define
ahora como el número de referencias a él que tengan dueño. El dueño de una referencia tiene la responsabilidad de
llamara a Py_DECREF() cuando no se necesite más la referencia. La propiedad de una referencia es transferible. Hay
tres modos de deshacerse de una referencia propia: Transferirla, almacenarla o llamar a Py_DECREF(). Si se olvida
deshacerse de una referencia propia se causará una pérdida de memoria.
También es posible tomar prestada3 una referencia al objeto. El que toma prestada la referencia no debe utilizar el
objeto más tiempo que su dueño. Si se usa una referencia prestada después de que el dueño se haya deshecho de ella,
hay un riesgo de que se utilice memoria liberada que se debe evitar por completo4 .
La ventaja de tomar prestada una referencia en lugar de poseerla estriba en que no hay que ocuparse de deshacerse
de la referencia en todo recorrido posible del código. Dicho con otras palabras, con una referencia prestada no hay
peligro de pérdidas en el caso de salidas prematuras. La desventaja es que hay situaciones muy sutiles en que código
aparentemente correcto utiliza una referencia prestada cuando su dueño ya se había deshecho de ella.
Se puede tomar posesión de una referencia prestada llamando a Py_INCREF(). Esto no afecta al estado del dueño
original de la referencia, sólo crea una nueva propiedad de la referencia y carga al nuevo propietario con las mismas
responsabilidades de dueño (es decir, el nuevo propietario debe deshacerse de la referencia correctamente, como
también debe el antiguo propietario).
3 Lametáfora de “tomar prestada” una referencia no es completamente fiel: el dueño mantiene una copia de la referencia.
4 Comprobar que el saldo de referencia es positivo no funciona el propio contador puede estar en memoria liberada y reasignada, por lo que
puede pertenecer a otro objeto.
Siempre que se mete o saca una referencia a un objeto de una función, es parte de la especificación de la interfaz de la
función si se transfiere la propiedad (en el sentido de posesión, no de característica) con la referencia o no.
La mayoría de las funciones que devuelven una referencia a un objeto traspasan la propiedad con la referencia. En
particular, todas las funciones cuyo propósito es la creación de un nuevo objeto, por ejemplo PyInt_FromLong()
y Py_BuildValue(), traspasan la propiedad al receptor. Aun en el caso en que, de hecho, el receptor no reciba
una referencia a un objeto nuevo del todo, se recibe la propiedad. Por ejemplo, PyInt_FromLong() mantiene una
caché de valores comunes y puede devolver una referencia a un elemento de la caché.
Muchas funciones que extraen objetos de otros objetos también traspasan la propiedad con la referencia, por
ejemplo PyObject_GetAttrString(). La cosa no está tan clara aquí, sin embargo, pues algunas ruti-
nas comunes no cumplen esto: PyTuple_GetItem(), PyList_GetItem(), PyDict_GetItem() y Py-
Dict_GetItemString() devuelven referencias prestadas de la tupla, lista o diccionario.
La función PyImport_AddModule() también devuelve una referencia prestada, aunque haya generado el objeto
devuelto: Esto es posible porque se almacena una referencia propia al objeto en sys.modules.
Al pasar una referencia a objeto a otra función, en general, la función toma prestada la referencia. Si necesita almace-
narla, utilizará Py_INCREF() para hacerse propietario independiente. Hay exactamente dos importantes excepciones
a esta regla: PyTuple_SetItem() y PyList_SetItem(). Estas funciones toman la propiedad del elemento que
reciben ¡aunque fracasen! PyDict_SetItem() y similares, sin embargo, no adquieren la propiedad, son “norma-
les”.
Cuando se llama a una función de C desde Python, toma prestadas las referencias de sus argumentos del llamante. El
llamante posee referencias a los objetos, por lo que la vida de la referencia prestada está garantizada hasta el retorno
de la función. Sólo cuando una de estas referencias prestadas se deba almacenar o pasar a su vez se debe convertir en
referencia propia llamando a Py_INCREF().
La referencia a objeto devuelta desde una función C llamada desde Python debe ser una referencia propia; se traspasa
la propiedad de la función a su llamante.
Hay unas cuantas situaciones en las la que el uso aparentemente inocua de una referencia prestada puede causar
quebraderos de cabeza. Todas tienen que ver con llamadas implícitas al intérprete, que pueden causar que el propietario
de una referencia se deshaga de ella.
La primera y más importante causa que hay que conocer es el uso de Py_DECREF() sobre un objeto independiente
mientras se toma prestada una referencia a un elemento de lista. Por ejemplo:
bug(PyObject *lista) {
PyObject *elemento = PyList_GetItem(list, 0);
PyList_SetItem(lista, 1, PyInt_FromLong(0L));
PyObject_Print(elemento, stdout, 0); /* ¡BUG! */
}
Esta función toma prestada una referencia a list[0], luego reemplaza list[1] con el valor 0 y, por último,
presenta la referencia prestada. Parece inofensivo, ¿no? Pues no.
Sigamos el flujo de control de PyList_SetItem(). La lista posee referencias a todos sus elementos, por lo que
cuando se reemplaza el elemento 1, se ha de deshacer del elemento 1 original. Supongamos ahora que dicho elemen-
to fuera una instancia de una clase definida por el usuario y que dicha clase definiera un método __del__(). Si
esta instancia de clase tuviera un saldo de referencias igual a 1, deshacerse de ella hará que se llame a su método
Py_INCREF(elemento);
PyList_SetItem(lista, 1, PyInt_FromLong(0L));
PyObject_Print(elemento, stdout, 0);
Py_DECREF(elemento);
}
Esto está basado en hechos reales. Una versión anterior de Python contenía variantes de este bug y alguien se pasó una
cantidad considerable de tiempo para descubrir por qué fracasaban sus métodos __del__(). . .
El segundo caso de problemas de referencias prestadas afecta a las hebras de ejecución. Normalmente, las múltiples
hebras de ejecución no se estorban, porque hay un bloque global que protege el espacio nominal de Python comple-
to. Sin embargo, es posible liberar este bloqueo usando la macro Py_BEGIN_ALLOW_THREADS y reactivarlo con
Py_END_ALLOW_THREADS. Esto es común en los bloques de llamadas E/S bloqueantes, para permitir que otras
hebras usen la CPU mientras se espera que se complete la E/S. Obviamente, la función siguiente presenta el mismo
problema que la anterior:
bug(PyObject *lista) {
PyObject *elemento = PyList_GetItem(lista, 0);
Py_BEGIN_ALLOW_THREADS
...llamada a E/S bloqueante...
Py_END_ALLOW_THREADS
PyObject_Print(elemento, stdout, 0); /* ¡BUG! */
}
En general, las funciones que toman referencias a objetos como argumentos no esperan que se les pasen punteros
NULL, y harán que el intérprete casque si se hace. Las funciones que devuelven referencias a objetos suelen devolver
NULL sólo si quieren indicar que ha ocurrido una excepción. La razón para no comprobar los argumentos NULL es
que las funciones pasan a menudo los objetos que reciben a otra función. Si cada función tuviera que comprobar los
NULL, habría una gran cantidad de comprobaciones redundantes, que ralentizarían el código.
Es mejor comprobar los NULL sólo en el “origen”, es decir, cuando se recibe un puntero que pudiera ser nulo, en
malloc() o desde una función que pueda lanzar una excepción.
Las macros Py_INCREF() y Py_DECREF() no comprueban los punteros NULL. Sin embargo, sí lo hacen sus
hermanas Py_XINCREF() y Py_XDECREF().
Las macros que verifican el tipo de objeto (Pytype_Check()) no comprueban si los punteros son NULL. De nuevo,
hay mucho código que llama a éstas en fila para comprobar diferentes tipos esperados, lo que causaría comprobaciones
redundantes. No hay versiones con comprobación de NULL.
El mecanismo de llamada a función de C garantiza que la lista de argumentos pasados a funciones C (args en los
static int
PySpam_System(command)
char *command;
{
return system(command);
}
static PyObject *
spam_system(self, args)
PyObject *self;
PyObject *args;
{
char *command;
int sts;
#include "Python.h"
#define SPAM_MODULE
#include "spammodule.h"
El #define se usa para indicar al fichero de cabecera que se está incluyendo en el módulo servidor, no en un módulo
cliente. Por último, la función de inicialización del módulo debe ocuparse de inicializar la matriz de punteros del API
de C:
Véase que PySpam_API se declara static; en caso contrario, ¡la matriz de punteros desaparecería al terminar la
ejecución de initspam!
El grueso del trabajo está en el fichero de cabecera ‘spammodule.h’, que tiene este aspecto:
#ifdef SPAM_MODULE
/* Esta sección se utiliza al compilar spammodule.c */
#else
/* Esta sección se utiliza en los módulos que utilizan el API de spammodule */
#define PySpam_System \
(*(PySpam_System_RETURN (*)PySpam_System_PROTO) PySpam_API[PySpam_System_NUM])
#define import_spam() \
{ \
PyObject *module = PyImport_ImportModule("spam"); \
if (module != NULL) { \
PyObject *module_dict = PyModule_GetDict(module); \
PyObject *c_api_object = PyDict_GetItemString(module_dict, "_C_API"); \
if (PyCObject_Check(c_api_object)) { \
PySpam_API = (void **)PyCObject_AsVoidPtr(c_api_object); \
} \
} \
}
#endif
#ifdef __cplusplus
}
#endif
#endif /* !defined(Py_SPAMMODULE_H */
Todo cuanto tiene que hacer un cliente para acceder a la función PySpam_System() es llamara a la función (más
bien macro) import_spam() en su función de inicialización:
Py_InitModule("client", ClientMethods);
import_spam();
}
La mayor pega de esta solución es que el fichero ‘spammodule.h’ es bastante complicado, Sin embargo, la estructura
básica es la misma para cada función a exportar, por lo que sólo hay que aprenderlo una vez.
Por último, hay que mencionar que los CObjects ofrecen funciones adicionales, especialmente para reserva y libe-
ración de memoria del puntero almacenado en un CObject. Los detalles están descritos en Manual de referencia
del API Python/C en la sección “CObjects” y en la implementación de los CObjects (ficheros ‘Include/cobject.h’ y
‘Objects/cobject.c’ de la distribución de fuentes de Python).
DOS
Empezando por Python 1.4, Python proporciona un “makefile” especial para generar makefiles para generar extensio-
nes de carga dinámica e intérpretes a medida. Este fichero especial genera makefiles que reflejan diversas variables
del sistema determinadas mediante el programa “configure” en el momento de construir el intérprete de Python, para
que los que vayan a generar módulos no tenga que volver a proporcionar estos valores. Esto simplifica sobremanera el
proceso de generación de extensiones e intérpretes a medida en sistemas Unix.
El makefile especial se distribuye en el fichero ‘Misc/Makefile.pre.in’ en la distribución de fuentes de Python. El primer
paso en la generación de extensiones e intérpretes a medida es copiar este makefile al directorio de desarrollo que
contiene los fuentes del módulo de extensión.
El makefile especial, ‘Makefile.pre.in’ usa metadatos proporcionados por el fichero ‘Setup’. El formato del fichero
‘Setup’ es el mismo que el del fichero ‘Setup’ (o ‘Setup.in’) del directorio ‘Modules/’ de la distribución de fuentes de
Python. ‘Setup’ contiene definiciones de variables:
EC=/projects/ExtensionClass
y líneas de descripción del modulo. Puede contener también líneas en blanco y comentarios que empiecen por ‘#’.
Una línea de descripción de módulo incluye un nombre de módulo, ficheros fuente opciones, referencias a variables y
otros ficheros de entrada, como bibliotecas o ficheros objeto. Considérese el siguiente ejemplo mínimo:
ExtensionClass ExtensionClass.c
Ésta es la forma más simple de línea de definición de módulo. Define un módulo, ExtensionClass, con un solo
fichero fuente, ‘ExtensionClass.c’.
Este ejemplo, ligeramente más complejo, utiliza una opción -I para especificar un directorio de ficheros incluidos:
EC=/projects/ExtensionClass
cPersistence cPersistence.c -I$(EC)
25
para indicar que los módulos definidos en ‘Setup’ han de ser generados como módulos de enlace dinámico. Se puede
usar una línea que contenga sólo ‘*static*’ para indicar que los módulos que sigan deben compilarse estáticamente.
He aquí un fichero ‘Setup’ completo para construir el módulo cPersistent:
Tras crear el fichero ‘Setup’, se ejecuta ‘Makefile.pre.in’ con ‘boot’ como objetivo para generar el makefile:
Con lo que se genera el fichero Makefile. Para generar las extensiones, basta con ejecutar make con el Makefile creado,
que se utiliza por omisión:
make
make static
Los módulos definidos en el fichero Setup antes de la línea ‘*shared*’ se enlazarán estáticamente al intérprete.
Típicamente, se omite la línea ‘*shared*’ en el fichero Setup si se desea obtener un intérprete a medida.
Opción Significado
-C Indicar al preprocesador de C que no descarte los comentarios
-Dname=value Definir una macro
-Idir Especificar un directorio de include, dir
-Ldir Especificar un directorio de bibliotecas de enlace estático, dir
-Rdir Especificar un directorio de bibliotecas de enlace dinámico, dir
-llib Enlazar una biblioteca, lib
-Uname Des-definir una macro
2.3 Ejemplo
He aquí un ejemplo más complicado de ‘Modules/Setup.in’:
GMP=/ufs/guido/src/gmp
mpz mpzmodule.c -I$(GMP) $(GMP)/libgmp.a
2.3. Ejemplo 27
28
CAPÍTULO
TRES
Este capítulo explica brevemente cómo crear un módulo de extensión para Python utilizando Microsoft Visual C++
y sigue con información avanzada sobre su funcionamiento. El material explicativo es útil para el programador de
Windows que está aprendiendo a construir extensiones de Python y para el programador de U NIX interesado en
producir software capaz de compilar en U NIX y Windows.
3.1 La receta
Esta sección proporciona una receta para construir una extensión de Python en Windows.
Bajar el instalador binario de http://www.python.org/ e instalar Python. El instalador binario contiene todas las cabeceras
requeridas excepto la cabecera necesaria ‘config.h’.
Bajar la distribución de fuentes y extraerla en una ubicación adecuada. Copiar el ‘config.h’ del directorio ‘PC/’ al
directorio ‘include/’ creado por el instalador.
Crear un fichero ‘Setup’ para el futuro módulo de extensión, según se describe en el capítulo 2.
Obtener el guion ‘compile.py’ de David Ascher desde http://starship.python.net/crew/da/compile/. Ejecutar el guion
para crear los ficheros de proyecto de Microsoft Visual C++.
Abrir el fichero DSW con Visual C++ y seleccionar Build.
Si el módulo crea nuevos tipos, la siguiente línea puede dar problemas:
PyObject_HEAD_INIT(&PyType_Type)
Cambiarla a:
PyObject_HEAD_INIT(NULL)
MyObject_Type.ob_type = &PyType_Type;
Se pueden obtener más detalles sobre esto en la sección 3 del FAQ de Python (http://www.python.org/doc/FAQ.html).
29
3.2 Diferencias entre U NIX y Windows
U NIX y Windows parten de paradigmas completamente diferentes para la carga de código en tiempo de ejecución.
Antes de intentar construir un módulo con carga dinámica, se debe comprender cómo funciona el sistema final del
usuario.
En U NIX, un fichero objeto compartido (shared object, ‘.so’) contiene código que será utilizado por el programa junto
con los nombres de las funciones y datos que espera encontrar en el programa. Cuando el fichero se une al programa,
se cambian todas las referencias a dichas funciones y datos para que apunten a sus direcciones de memoria reales en
el programa. A grandes rasgos, se realiza una operación de enlace.
En Windows, un fichero de biblioteca de enlace dinámico, (dynamic-link library, ‘.dll’) no tiene referencias pendientes.
En lugar de ello, todo acceso a funciones y datos pasa por una tabla de consulta. Por ello, no hay que arreglar el código
de la DLL para que haga referencia a la memoria del programa. El programa ya utiliza la tabla de búsquedas, lo que
cambia en tiempo de ejecución es la tabla de búsquedas para apuntar a las funciones y datos finales.
En U NIX, sólo hay un tipo de fichero de biblioteca (‘.a’) que contiene código de varios ficheros objeto (‘.o’). En el
paso de enlace para crear un fichero objeto compartido (‘.so’), el enlazador puede encontrarse que desconoce dónde
se define un identificador. El enlazador lo buscará en los ficheros objeto y en las bibliotecas. Si lo encuentra, incluirá
todo el código del fichero objeto.
En Windows, existen dos tipos de biblioteca, una biblioteca estática y una biblioteca de importación (ambas llamadas
‘.lib’). Una biblioteca estática es como un fichero ‘.a’ de U NIX: contiene código que se incluirá si es necesario.
Una biblioteca de importación se usas sólo para asegurar al enlazador que un identificador concreto es legal y estará
presente en el programa cuando se cargue la DLL. Por ello, el enlazador utiliza la información de la biblioteca de
importación para construir la tabla de consulta para usar los identificadores no incluidos en la DLL. Cuando se enlaza
una aplicación o DLL, puede generarse una biblioteca de importación, que tendrá que usarse para futuras DLLs que
dependan de los símbolos de la aplicación o DLL.
Supóngase que se están construyendo dos módulos de carga dinámica, B y C, que han de compartir otro bloque de
código A. En U NIX, no se pasaría ‘A.a’ al enlazador para ‘B.so’ y ‘C.so’; eso causaría que se incluyera dos veces y
tanto B como C tendrían su propio ejemplar. En Windows, al construir ‘A.dll’ se construiría ‘A.lib’. Sí se pasaría ‘A.lib’
al enlazador tanto en B como en C. ‘A.lib’ no contiene código, sólo 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 análogo a usar ‘import spam’; proporciona acceso a los nom-
bres de spam, pero no genera una copia aparte. En U NIX, enlazar con una biblioteca es más como ‘from spam
import *’; sí genera una copia aparte1 .
La primera orden genera tres ficheros: ‘spam.obj’, ‘spam.dll’ y ‘spam.lib’. ‘Spam.dll’ no contiene ninguna función de
Python (del estilo de PyArg_ParseTuple()), pero sabe como acceder al código de Python gracias a ‘python15.lib’.
La segunda orden genera ‘ni.dll’ (además de ‘.obj’ y ‘.lib’), que dispone de información para acceder a las funciones
1 N. del T.: No estoy seguro de que haber comprendido la explicación, o la analogía no es muy buena.
CUATRO
Empotrar Python es parecido a extenderlo, pero no igual. La diferencia radica en que al extender Python, el programa
principal de la aplicación sigue siendo el intérprete de Python, mientras que al empotrar Python, el programa principal
puede no tener nada que ver con Python, ocasionalmente alguna parte del programa invocará al intérprete para que
ejecute cierto código Python.
Por ello, al empotrar Python, se debe proporcionar el programa principal. Una de las cosas que debe hacer el programa
principal es inicializar el intérprete de Python. Como mínimo, hay que llamar a la función Py_Initialize() (en
MacOS, a la función PyMac_Initialize()). Hay llamadas opcionales para pasar argumentos de línea de órdenes
a Python. Más tarde, se puede llamar al intérprete desde cualquier lugar de la aplicación.
Hay varias maneras de llamar al intérprete: se puede pasar una cadena que contenga sentencias de Python a Py-
Run_SimpleString() o pasar un puntero al fichero stdio y un nombre de fichero (tan sólo para identificación
de los mensajes de error) a PyRun_SimpleFile(). También se puede llamar a las operaciones de nivel inferior
descritas en los anteriores capítulos para construir y usar objetos de Python.
Se puede encontrar una sencilla demostración de empotrado de Python en el directorio ‘Demo/embed/’ de la distribu-
ción de fuentes.
33
>>> import distutils.sysconfig
>>> distutils.sysconfig.LINKFORSHARED
’-Xlinker -export-dynamic’
El contenido de la cadena presentada será el bloque de opciones que se deben usar. Si la cadena aparece vacía, no es
necesario añadir opciones adicionales. La definición de LINKFORSHARED se corresponde con la variable del mismo
nombre del ‘Makefile’ principal de Python.
Informes de error
Python es un lenguaje de programación maduro que se ha ganado reputación por su estabilidad. Para mantener esta
reputación, los desarrolladores agradecerían recibir noticia de cualquier deficiencia que encuentres en Python o su
documentación.
Se deben enviar todos los informes de error mediante el Seguimiento de errores de Python (Python Bug Tracker),
ubicado en SourceForge (http://sourceforge.net/bugs/?group_id=5470). El seguimiento de errores propociona un for-
mulario Web que permite rellenar la información pertinente y enviarla a los desarrolladores.
Antes de enviar un informe, se ruega entrar en SourceForge si eres miembro. Esto permitirá a los desarrolladores po-
nerse en contacto contigo para obtener información adicional, si fuera necesario. Si no eres miembro de SourceForge,
pero no te importa que los desarrolladores se pongan en contacto contigo, puedes incluir tu dirección en la descripción
del error. En tal caso, sé consciente de que la información quedará disponible para el público.
El primer paso para rellenar un informe es determinar si el problema ya ha sido informado. La ventaja de hacer esto,
además de ahorrar el tiempo de los desarrolladores, es que puedes enterarte de lo que se ha hecho para solucionarlo.
Puede ser que ya esté resulelto en la siguiente versión o que haga falta información adicional (¡en tal caso, estás
invitado a proporcionarla si puedes!). Para hacerlo, busca en la base de datos de errores usando la caja de búsqueda
del final de la página.
Si el problema que estás enviando no está ya en el seguimiento de errores, vuelve al seguimiento
(http://sourceforge.net/bugs/?group_id=5470). Selecciona el enlace “Submit a Bug”, enviar un error, del principio de
la página para abrir el formulario de envío de errores.
El formulario de envío tiene varios campos. Los únicos exigidos son los de “Resumen” y “Detalles”. Para el resu-
men, introduce un descripción muy breve del problema; menos de diez palabras está bien. En el campo de detalles,
describe el problema en detalle, incluyendo el resultado esperado y obtenido. Asegúrate de incluir el número de ver-
sión de Python utilizado, si había módulos de extensión involucrados y la plataforma hardware y software (incluidas
versiones).
El otro campo que te podría interesar es el de “Categoría”, que permite clasificar el informe de error en una categoría
amplia (como “Documentación” or “Biblioteca”).
Cada informe de error se asignará a un desarrollador, que determinará qué hay que hacer para corregir el problema. Si
tienes una cuenta en Sourceforge y habías iniciado una sesión cuando diste de alta el informe de error, recibirás una
actualización cada vez que se tomen acciones para solucionar el problema.
See Also:
Cómo dar partes de error eficaces
(http://www-mice.cs.ucl.ac.uk/multimedia/software/documentation/ReportingBugs.html)
Artículo que entra en cierto detalle de cómo crear un parte de error útil. Describe qué tipo de información es útil
y por qué es útil.
Libro de estilo de errores
(http://www.mozilla.org/quality/bug-writing-guidelines.html)
35
Información sobre la escritura de buenos informes de error. Hay cosas específicas del proyecto Mozilla, pero
describe buenas normas generales.