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 internatotal
.
>>> 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ónsuma()
donde utilizamos la función integradatype()
para imprimir el tipo de dato deargs
.
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()
dekwargs
, 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:
- Argumentos estándar
- Argumentos
*args
- 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.
Hola, muchas gracias
Muy buena explicación de algo que aparece siempre como sabido respecto a los argumetos para decoradores.
De nada Emilio, me alegro que te haya gustado.