Argumentos en funciones (*args y **kwargs)

Argumentos en funciones (*args y **kwargs)

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

Esta es la notación convencional, en donde los tres argumentos son requeridos. En caso de que alguno de los tres no sea especificado, 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 de 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, este 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 valores serán guardados en el primer parámetro (args), todo argumento posterior necesariamente se convierte en un argumento clave-valor:

>>> def f(*args, b):
...     return args, b
...
>>> # b solo puede especificarse a través del nombre.
>>> f(1, 2, b=3)
((1, 2), 3)

Si omitiéramos el nombre del argumento b, el valor 3 quedaría capturado por *args, haciendo que Python se queje ante la ausencia de b:

>>> f(1, 2, 3)
TypeError: f() missing 1 required keyword-only argument: 'b'

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.

Curso online 👨‍💻

¡Ya lanzamos el curso oficial de Recursos Python en Udemy! Un curso moderno para aprender Python desde cero con programación orientada a objetos, SQL y tkinter en 2024.

Consultoría 💡

Ofrecemos servicios profesionales de desarrollo y capacitación en Python a personas y empresas. Consultanos por tu proyecto.

8 comentarios.

  1. Que buen tutorial. Los conocimientos adquiridos sobre este lenguajes han sido de videos de Youtube, pero muchas veces dan por hecho estos temas. Ya voy despegando y solo ahora me queda claro el tema de los args y kwargs. Muchas gracias!!

  2. 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 una respuesta