diferencias entre PyArg_ParseTuple y PyArg_ParseTupleAndKeywords?
Gabriel Genellina
gagsl-py2 en yahoo.com.ar
Sab Mayo 3 01:47:44 CEST 2008
En Thu, 01 May 2008 20:37:20 -0300, Milton Galo Patricio Inostroza
Aguilera <minoztro en gmail.com> escribió:
> Me he animado a aprender a programar modulos en c para python {para
> poder luego entender la implementacion misma del lenguaje}...y me he
> encontrado con estas dos funciones.
>
> En realidad no noto cual es la diferencia de uso de estas dos
> funciones, si bien es cierto que tienen una declaracion distintas
> (argumentos), en la utilizacion de estas no puedo ver la diferencia
> entre una y otra...muestro un ejemplo {que es el que esta en el manual
> de extending and embedding python}:
PyArg_ParseTuple solo procesa argumentos posicionales. Es decir, a la
funcion hay que pasarle una tupla con los argumentos en el orden exacto en
que estan declarados. La funcion en C tiene normalmente esta forma:
PyObject *
funcion(PyObject *self, PyObject *args)
{
...
}
En Python es como si hubiera sido declarada asi:
def funcion(*args):
PyArg_ParseTupleAndKeywords procesa argumentos posicionales y nominales.
Los argumentos posicionales se pasan en una tupla; los nominales en un
diccionario. En C la funcion normalmente esta declarada asi:
PyObject *
funcion(PyObject *self, PyObject *args, PyObject *kwds)
{
...
}
En Python es como si la declaracion hubiera sido:
def funcion(*args, **keywds):
Si la funcion espera argumentos por posicion exclusivamente (es decir, usa
PyArg_ParseTuple), NO se le pueden pasar por nombre. Ejemplo:
py> help(file.seek)
Help on method_descriptor:
seek(...)
seek(offset[, whence]) -> None. Move to new file position.
Argument offset is a byte count. Optional argument whence [...]
Ahi dice que el primer argumento de seek se llama offset. Pero no se lo
podemos pasar por nombre:
py> open("un/archivo/que/exista").seek(offset=123)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: seek() takes no keyword arguments
Mirando la documentacion exclusivamente, NO hay forma de saber si una
funcion espera ser llamada con argumentos posicionales o nominales.
> static PyObject *
> keywdarg_parrot(PyObject *self, PyObject *args, PyObject *keywds)
> {
> int voltage;
> char *state = "a";
> char *action = "a";
> char *type = "a";
>
> static char *kwlist[] = {"state", "action", "type","voltage", NULL};
> if (!PyArg_ParseTupleAndKeywords(args, keywds, "i|sss",kwlist,
> &voltage,&state,&action,&type))
>
> printf("%s %i \n",action,voltage);
> printf("%s %s \n",state,type);
> Py_INCREF(Py_None);
> return Py_None;
> }
>
>
> si en vez de utilizar el PyArg_ParseTupleAndKeywords, utilizo
> PyArg_ParseTuple de la siguiente manera:
>
> if(!PyArg_ParseTuple(args,"i|sss",&voltage,&state,&action,&type))
> return NULL;
>
> El resultado es el mismo...entonces no se por donde pasa la diferencia
El resultado es el mismo *sólo* si la llamada la haces con una tupla que
contiene los argumentos en ese mismo orden. Trasladado mas o menos en
Python, el primer caso es:
def funcion(*args, **kwargs):
state = 'a'
action = 'a'
type = 'a'
voltage = args.pop(0)
assert not args, "argumento posicional inesperado: %r" % args
# el if está porque es opcional
if 'state' in kwargs: state = kwargs.pop('state')
if 'action' in kwargs: action = kwargs.pop('action')
if 'type' in kwargs: type = kwargs.pop('type')
assert not kwargs, "argumento nominal inesperado: %r" % kwargs
y el segundo:
def funcion(*args):
state = 'a'
action = 'a'
type = 'a'
voltage = args.pop(0)
# estos otros son opcionales
if args: state = args.pop(0)
if args: action = args.pop(0)
if args: type = args.pop(0)
assert not args, "argumento posicional inesperado: %r" % args
(con la diferencia de que esos pop() NO modifican la tupla/diccionario
originales)
> de uso de estas dos funciones...y me queda otra duda cual es la mision
> de kwlist, tampoco la entiendo mucho..porque si en vez de poner los
> nombre de las variables y pongo cualquier cosa, el modulo cuando lo
> importo desde python funciona igualmente bien, la modificacion que
> realice a kwlist es la siguiente:
>
> static char *kwlist[] = {"algo", "algodos", "algotres","algocuatro",
> NULL};
Lo que esta a la derecha de la | es opcional; asi que si tu formato era el
mismo de arriba ("i|sss") entonces solo el primer argumento "algo" era
obligatorio; si se lo pasaste en la tupla args entonces todos los demás
eran opcionales y podian no existir. Ademas en el primer ejemplo veo que
no estas verificando bien el codigo de retorno de PyArg_ParseXXX (que
probablemente devolvio NULL) asi que si te dio error, no te enteraste.
--
Gabriel Genellina
------------ próxima parte ------------
_______________________________________________
Lista de correo Python-es
http://listas.aditel.org/listinfo/python-es
FAQ: http://listas.aditel.org/faqpyes
Más información sobre la lista de distribución Python-es