diferencias entre PyArg_ParseTuple y PyArg_ParseTupleAndKeywords?
Milton Galo Patricio Inostroza Aguilera
minoztro en gmail.com
Sab Mayo 3 03:54:22 CEST 2008
2008/5/2 Gabriel Genellina <gagsl-py2 en yahoo.com.ar>:
> 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.
Ufff, excelente explicacion...me ha quedado muy claro, muchas gracias :)
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.
>
oumm, la verificacion la estoy haciendo igual como en el manual
oficial [1] y en la referencia dice que PyArg_ParseTuple retorna un
false o un simil [2]. Como crees tu que sea mejor, ya que veo que
tienes mas experiencia y la idea es siempre aprender de los que saben
mas :)
[1] http://docs.python.org/ext/backToExample.html
Going back to our example function, you should now be able to
understand this statement:
if (!PyArg_ParseTuple(args, "s", &command))
return NULL;
[2] http://docs.python.org/api/arg-parsing.html#l2h-210
> --
> Gabriel Genellina
>
>
> _______________________________________________
> Lista de correo Python-es
> http://listas.aditel.org/listinfo/python-es
> FAQ: http://listas.aditel.org/faqpyes
>
--
Milton Inostroza Aguilera
------------ 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