Python » Python Avanzado » Guía de *args y **kwargs en Python

Guía de *args y **kwargs en Python

Si llevas tiempo programando en Python es probable que en algún momento te hayas cruzado con los argumentos *args y **kwargs. En este post vamos a ver qué son estos dos parámetros, así como ejemplos de cuándo usarlos. Antes de empezar, comentar que ambos términos vienen del inglés, concretamente *args significa arguments (argumentos) y **kwargs significa keyword arguments (argumentos de palabras clave). Ambos nombres son una convención y podemos nombrarlos como queramos, ya que lo que es realmente importante es el uso del asterisco (*) y el doble asterisco (**). Sin embargo, siempre es recomendable seguir la convención de nomenclatura especialmente si nuestro código va a ser leído por otros programadores.

¿Qué es *args?

Veamos primero una función a la que llamamos suma() que simplemente retorna el resultado de sumar sus dos argumentos posicionales.

def suma(a, b):
    return a + b 

Si usamos la función pasándole dos argumentos, ésta funciona correctamente. En cambio, como es de esperar, si le pasamos tres argumentos Python nos da un error.

>>> suma(1, 2)
3
>>> suma(1, 2, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: suma() takes 2 positional arguments but 3 were given

Entonces, si queremos sumar tres números ¿tenemos que crear una nueva función para cubrir este caso? ¿Y si además de sumar tres números también tenemos que sumar cuatro? Aquí es donde entra en juego *args. Este parámetro se utiliza para indicar que la función utiliza un número variable de argumentos posicionales. Teniendo en cuenta esto podemos redefinir nuestra función suma() de la siguiente manera.

def suma(*args):
    total = 0
    for n in args:
        total += n
    return total

Con esta nueva definición ya podemos hacer sumas de tantos números como queramos.

>>> suma(1, 2)
3
>>> suma(1, 2, 3)
6
>>> suma(1, 2, 3, 4)
10

Llegados a este punto, veamos dos aspectos importantes de *args.

  • El uso de *args es opcional. Es decir, en nuestro ejemplo es perfectamente válido llamar a la función suma() sin pasarle ningún argumento, en cuyo caso nos retorna 0 que es el valor por defecto de la variable interna total.
>>> suma()
0
  • Los argumentos posicionales que pasamos como *args se guardan en una tupla dentro de la función. Esto podemos verlo fácilmente si añadimos una nueva línea a la función suma() donde utilizamos la función integrada type() para imprimir el tipo de dato de args.
def suma(*args):
    print(type(args))
    total = 0
    for n in args:
        total += n
    return total

Al ejecutar de nuevo la función, vemos que efectivamente args se trata como una tupla dentro de la función.

>>> suma(1, 2)
<class 'tuple'>
3

¿Qué es **kwargs?

Como hemos visto en la introducción **kwargs hace referencia a los argumentos definidos mediante palabras clave. Veamos ahora una función a la que llamamos persona(), la cual imprime los valores de sus tres argumentos que son: nombre, altura y peso.

def persona(nombre, altura, peso):
    print("Nombre :", nombre)
    print("Altura :", altura)
    print("Peso :", peso)

Como la función persona() tiene tres argumentos, sólo podemos llamarla pasándole los tres argumentos que espera. Aunque si usamos argumentos de palabras clave, no necesariamente tenemos que respectar el orden en el que los hemos definido en la función.

>>> persona(peso=85, nombre="Miguel", altura=187)
Nombre : Miguel
Altura : 187
Peso : 85

Si queremos pasarle a persona() otras variables como la edad, ¿tenemos que añadir más código a la función? ¿Y si más adelante quisiéramos pasarle aún más variables? En ese caso podemos reescribir nuestra función con la ayuda de **kwargs para hacerla más general. Este parámetro indica que la función acepta un número variable de argumentos de palabras clave.

def persona(**kwargs):
    for clave, valor in kwargs.items():
        print(clave, ":", valor)

Con esta nueva definición podemos pasarle a la función tantos parámetros de palabras clave como queramos.

>>> persona(nombre="Miguel", altura=187, peso=85, edad=36, pulso=52)
nombre : Miguel
altura : 187
peso : 85
edad : 36
pulso : 52

Si nos fijamos en la última definición del método persona(), podemos sacar dos conclusiones sobre **kwargs.

  • El uso de **kwargs es opcional. Es decir, si ejecutamos el método persona() sin ningún argumento no obtenemos ningún error.
>>> persona()
  • Los argumentos de palabras clave que pasamos como **kwargs se guardan en un diccionario dentro de la función. En el código hemos llamado al método items() de kwargs, el cual es un método propio de los diccionarios.

Orden de los argumentos en una función

Ahora que sabemos qué son *args y **kwargs ya podemos usarlos en nuestras funciones. Sin embargo, si queremos combinarlos con otros argumentos, tenemos que respetar el siguiente orden:

  1. Argumentos estándar
  2. Argumentos *args
  3. Argumentos **kwargs

El siguiente bloque de código ejemplifica una función bien definida:

def funcion(x, y, *args, **kwargs):
    pass

Ejemplos de uso

Subclases

Los parámetros *args y **kwargs pueden ser útiles para heredar de una clase padre sin necesidad de replicar la signatura de su constructor en la clase hijo. Veamos que significa esto con un ejemplo.

class Animal:
    def __init__(self, nombre, color):
        self.nombre = nombre
        self.color = color


class AnimalVerde(Animal):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.color = "verde"

En este caso, el atributo color de una instancia de la clase AnimalVerde siempre va a tener el mismo valor. Esto sucede porque el constructor de AnimalVerde pasa todos los argumentos al constructor padre y sobrescribe el valor de uno de los atributos.

>>> AnimalVerde("Gustavo", "rojo").color
'verde'

El inconveniente de esto es que no podemos saber qué atributos espera el constructor de la clase AnimalVerde sin ver el constructor de la clase Animal. Por tanto, cuando tiene más sentido usar esta técnica es cuando queremos modificar o sobrescribir el comportamiento de una clase externa sobre la que no tenemos control.

Decoradores

Otro caso donde *args y **kwargs vienen como anillo al dedo es cuando definimos nuestros propios decoradores. Sin embargo, ejemplificarlo aquí resultaría en un post muy largo. Si estás interesado en este tema puedes consultar el artículo donde desarrollo los decoradores en Python.

Conclusión

En este post hemos visto qué son *args y **kwargs en Python, así como algunos ejemplos de cuándo usarlos. Los aspectos más importantes a recordar son los siguientes:

  • El uso de *args y **kwargs da flexibilidad a una función ya que le permiten tomar un número variable de argumentos.
  • *args pasa un número variable de argumentos posicionales que se tratan como una tupla dentro de la función.
  • **kwargs pasa un número variable de argumentos de palabras clave que se tratan como un diccionario dentro de la función.
Foto del autor

Albert Brugués

Soy doctor en informática médica y un apasionado de la tecnología y las nuevas oportunidades que brinda. Más en particular me encanta la inteligencia artificial y el desarrollo web. En este blog pretendo compartir los conocimientos de Python que he ido adquiriendo a lo largo de los años.

2 comentarios en «Guía de *args y **kwargs en Python»

  1. Hola, muchas gracias
    Muy buena explicación de algo que aparece siempre como sabido respecto a los argumetos para decoradores.

    Responder

Deja un comentario