Argumentos en funciones (*args y **kwargs)



Versión: 2.x, 3.x

Existen dos tipos de argumentos en Python: los convencionales y aquellos que están sujetos a un nombre específico, generalmente identificados como args (arguments) y kwargs (keyword arguments), respectivamente. Encontrar un término en el español para estos últimos resulta algo complejo, equivaldría a “argumentos de palabras clave”, así que simplemente los llamaremos por su nombre original.

def f(a, b, c):
    return a + b*c

Ésta es la notación convencional, en donde los tres argumentos son requeridos. En caso de no ser especificados, Python lanza una excepción.

>>> f(2, 5)
TypeError: f() takes exactly 3 arguments (2 given)
>>> f()
TypeError: f() takes exactly 3 arguments (0 given)
>>> f(2, 5, 3)
17

Sin embargo, todos los argumentos pueden tener un valor por defecto en caso que no sean especificados.

def h(a, b=4, c=2):
    return a + b*c

En este caso, Python lanzará una excepción únicamente cuando a no tenga un valor.

>>> h(1)  # a=1, b=4 y c=2
9
>>> h(1, 5, 6)  # a=1, b=5 y c=6
31
>>> h()
TypeError: h() takes at least 1 argument (0 given)

Cuando en una función uno de sus argumentos lleva un valor por defecto, éste se convierte automáticamente en un keyword argument o argumento clave-valor, tal como un diccionario. Por lo tanto, pueden ser especificados indicando su nombre al momento de invocarlos. Por ejemplo, si se quiere pasar un valor en el argumento c mientras que b mantenga aquél por defecto.

>>> h(1, c=10)
41

Y viceversa, por lo que ambos ejemplos a continuación resultan en lo mismo.

>>> h(1, b=5)
11
>>> h(1, 5)
11

Al indicar el nombre de los argumentos clave-valor, las posiciones de estos son indiferentes.

>>> h(1, c=10, b=6)
61
>>> h(1, 6, 10)
61

Los argumentos pueden llevar cualquier valor por defecto, incluyendo None y llamadas a otras funciones.

>>> def a(c=None):
...     return 100
...
>>> def b(n=a()):
...     return n + 50
...
>>> b()
150


Una de las principales diferencias entre los dos tipos de argumentos, como observamos anteriormente, es que los convencionales son posicionales, mientras que en los keyword arguments su ubicación es indistinta.

Al ser un lenguaje interpretado Python presenta mucha flexibilidad. Por ejemplo, para que una función tome una cantidad indefinida de argumentos, se utiliza la expresión *args.

>>> def f(*args):
...     return args
...
>>> f(1, 5, True, False, "Hello, world!")
(1, 5, True, False, 'Hello, world!')

En este caso, args es una tupla que contiene todos los valores que se han pasado a la función. El signo asterisco (*) es utilizado para indicar dicha funcionalidad; de lo contrario, únicamente el primer argumento sería almacenado en args.

Dado que todos los argumentos serán guardados en el primer parámetro (args), Python lanzará una excepción al intentar especificar algún otro luego de éste.

    def f(*args, b):
                 ^
SyntaxError: invalid syntax

De forma análoga funcionan los keyword arguments, que son representados con dos asteriscos (**) y el nombre kwargs. Cabe destacar que los nombres de estos parámetros son indiferentes; args y kwargs son utilizados simplemente por convención.

>>> def f(**kwargs):
...     return kwargs
...
>>> f(a=1, b=True, h=50, z="Hello, world!")
{'a': 1, 'h': 50, 'b': True, 'z': 'Hello, world!'}

En este caso kwargs es un diccionario que contiene el nombre de cada uno de los argumentos junto con su valor. Siendo esto así, el orden de los mismos es indistinto.

Ambos métodos pueden ser implementados en una misma función como excepción al error de sintaxis.

>>> def f(*args, **kwargs):
...     return args, kwargs
...
>>> args, kwargs = f(True, False, 3.5, message="Hello, world!", year=2014)
>>> args
(True, False, 3.5)
>>> kwargs
{'message': 'Hello, world!', 'year': 2014}

Los signos * y ** pueden también ser utilizados para almacenar argumentos en un objeto para ser pasados luego a una función. Considerando la función:

def f(a, b, c):
    return a*b**c

El siguiente código…

>>> argumentos = (5, 10, 2)
>>> f(*argumentos)
500

…resulta similar a:

>>> f(5, 10, 2)
500

De la misma forma funcionan los keyword arguments.

>>> def f(message="Hello", name=None):
...     print("{0}, {1}!".format(message, name))
...
>>> kwargs = {"message": "Hola", "name": "mundo"}
>>> f(**kwargs)
Hola, mundo!

Al momento de observarlo carece de sentido almacenar previamente los argumentos de una función. Sin embargo, les aseguro que les será de utilidad muchas veces en vuestros diversos proyectos.



2 comentarios.

  1. Es la mejor explicación que he encontrado sobre los argumentos en funciones en Python, y eso que ya voy leyendo un buen puñado de manuales sobre Python, felicitaciones, estoy justo por entrar a ver interfaces gráficas, muy buena página, saludos.

Deja un comentario