1.7 Cadenas de formato para PyArg_ParseTuple()

La función PyArg_ParseTuple() se declara así:

int PyArg_ParseTuple(PyObject *arg, char *format, ...);

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" almacena 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.

Lee una variable de C y almacena en dos. La variable leída es un puntero a una cadena de nombre de codificación (encoding). La primera variable destino es un puntero a un puntero a una cadena (**buffer, utilizada para almacenar los datos codificados y la otra un puntero a un entero (*buffer_length, la longitud de la cadena).

El nombre de la codificación debe ser uno de los códec registrados. De ser NULL, se utilizará la codificación predeterminada.

PyArg_ParseTuple() reservará un bloque del tamaño adecuado mediante PyMem_NEW(), copiará los datos codificados a este bloque y ajustará *buffer para que apunte al nuevo almacenamiento. El que llama es responsable de llamar a PyMem_Free() para liberar el bloque reservado tras su uso.

"es#" (cadena, objeto Unicode o cualquier objeto legible con read) [const char *encoding, char **buffer, int *buffer_length]
Esta variación sobre "s#" se utiliza para codificar objetos Unicode y compatibles a cadena de caracteres. Lee de una variable de C y almacena en dos. La variable leída es un puntero a una cadena de nombre de codificación (encoding), la primera escrita es un puntero a un puntero a una cadena de caracteres (**buffer, que se utiliza para almacenar los datos codificados y la última un puntero a un entero *buffer_length, la longitud de la cadena.

El nombre de la codificación debe ser uno de los códec registrados. De ser NULL, se utilizará la codificación predeterminada.

Hay dos modos de funcionamiento:

Si *buffer apunta a un puntero NULL, PyArg_ParseTuple() reservará un bloque del tamaño necesario con PyMem_NEW(), copiará los datos codificados a este bloque y ajustará *buffer para que haga referencia al almacenamiento recién reservado. El que llama a esta función es responsable de llamara a PyMem_Free() para liberar el bloque reservado, tras su uso.

Si *buffer apunta a un puntero no NULL (un bloque ya reservado), PyArg_ParseTuple() utilizará esta ubicación e interpretará que *buffer_length es el tamaño del bloque utilizable. Entonces, copiará los datos codificados al bloque y les dará una terminación cero. Se señala el desbordamiento del bloque mediante una excepción.

En los dos casos, se actualiza *buffer_length a la longitud de los datos codificados, excluyendo el byte cero final.

"b" (integer) [char]
Convierte un entero de Python a un entero pequeño, almacenado en un char de C.

"h" (integer) [short int]
Convierte un entero de Python a un short int de C.

"i" (integer) [int]
Convierte un entero de Python a un int de C.

"l" (integer) [long int]
Convierte un entero de Python a un long int de C.

"c" (string of length 1) [char]
Convierte un carácter de Python, es decir, una cadena de caracteres de longitud uno, a un char de C.

"f" (float) [float]
Convierte un número de coma flotante de Python a un float de C.

"d" (float) [double]
Convierte un número de coma flotante de Python a un double de C.

"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.

"O&" (objeto) [conversión, anything]
Convierte un objeto de Python a una variable C mediante una función converter de conversión, que debe tomar dos argumentos: el primero es una función, el segundo es la dirección de una variable C (de tipo arbitrario), convertida a void *. Se invoca la función converter de este modo:

status = conversión(objeto, dirección);

donde objeto es el objeto de Python a convertir y dirección es el argumento void * pasado a PyArg_ConvertTuple(). El estado devuelto debería ser 1 para la conversión con éxito 0 si fracasó la conversión. Si la conversión falla, la función conversión debería lanzar una excepción.

"S" (cadena) [PyStringObject *]
Como "O", pero necesita que el objeto Python sea un objeto cadena. Lanza TypeError si no lo es. También se puede declarar la variable de C como PyObject *.

"U" (cadena Unicode) [PyUnicodeObject *]
Como "O", pero necesita que el objeto Python sea un objeto Unicode. Lanza TypeError si no lo es. También se puede declarar la variable de C como PyObject *.

"t#" (bloque de caracteres de sólo lectura) [char *, int]
Como "s#", pero acepta la interfaz de sólo lectura mediante read. La variable char * se hace apuntar al primer byte del bloque y se asigna al int la longitud del bloque. Sólo se aceptan bloques de un sólo segmento, se lanza TypeError en otros casos.

"w" (bloque de caracteres de lectura/escritura) [char *]
Como "s", pero acepta la interfaz de lectura-escritura mediante read/write. El que llama a la función debe determinar la longitud del bloque por otros medios, o usar "w#" en lugar de ésta. Sólo se aceptan bloques de un sólo segmento, se lanza TypeError en otros casos.

"w#" (bloque de caracteres de lectura/escritura) [char *, int]
Como "s#", pero acepta la interfaz de lectura-escritura mediante read/write. La variable char * se hace apuntar al primer byte del bloque y se asigna al int la longitud del bloque. Sólo se aceptan bloques de un sólo segmento, se lanza TypeError en otros casos.

"(elementos)" (tupla) [mismo nº elementos]
El objeto debe se una secuencia de Python cuya longitud es el número de unidades de formato de elementos. Los argumentos C deben corresponder con las unidades de formato individuales de elementos. Se puede anidar las unidades de formato.

Nota: En las versiones de Python anteriores a 1.5.2, este especificador de formato sólo aceptaba una tupla que contenía los parámetros individuales, no una secuencia arbitraria. El código que lanzara anteriormente TypeError puede proseguir ahora sin lanzar excepciones. No se espera que esto sea un problema para el código existente.

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 correspondientes 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:

    int vale;
    int i, j;
    long k, l;
    char *s;
    int tamanho;

    vale = PyArg_ParseTuple(args, ""); /* Sin argumentos */
        /* Llamada desde Python: f() */

    vale = PyArg_ParseTuple(args, "s", &s); /* Una cadena */
        /* Posible llamada desde Python: f('¡ahí va!') */

    vale = PyArg_ParseTuple(args, "lls", &k, &l, &s); /* Dos enteros y una cadena */
        /* Posible llamada desde Python: f(1, 2, 'tres') */

    vale = PyArg_ParseTuple(args, "(ii)s#", &i, &j, &s, &tamanho);
        /* Dos enteros y una cadena, cuyo tamaño se devuelve también */
        /* 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) */
    }


Ver Sobre este documento... para obtener información sobre sugerencias.