Argumentos en Python: *args, **kwargs y valores predeterminados
Esta lección es una traducción del original en inglés.Read in EnglishAvisar de un error de traducción
Piensa en cuando pides un café. Siempre tienes que elegir un tamaño: eso es obligatorio. ¿Pero los extras, como leche de avena, un espresso extra o un chorrito de caramelo? Esos son opcionales. Solo los mencionas cuando los quieres.
Los argumentos de las funciones de Python funcionan igual. Algunos son obligatorios, otros tienen valores predeterminados razonables y otros te dejan pasar tantos extras como quieras. Dominar estos patrones es lo que distingue a un principiante de alguien que escribe código realmente flexible.
En este tutorial aprenderás todas las formas en que Python te deja pasar datos a las funciones, desde los argumentos posicionales básicos hasta los potentes patrones *args y **kwargs que se usan en las bibliotecas reales.
Argumentos posicionales y argumentos con nombre
Cuando llamas a una función, Python asigna los argumentos a los parámetros de dos maneras. Los argumentos posicionales se asignan según su posición: el primer argumento va al primer parámetro. Los argumentos con nombre (keyword arguments) se asignan por su nombre.
Whiskers is a cat Buddy is a dog
Con los argumentos con nombre, escribes parameter_name=value. Así la llamada se explica sola: cualquiera que lea el código ve exactamente qué significa cada valor, sin tener que mirar la definición de la función.
Puedes mezclar los dos estilos en la misma llamada, pero los argumentos posicionales deben ir antes que los argumentos con nombre.
Whiskers is a 3-year-old cat
Cómo los valores predeterminados hacen flexibles las funciones
Los valores predeterminados te permiten definir parámetros opcionales. Si quien llama a la función da un valor, se usa ese. Si no, entra en juego el valor predeterminado.
large coffee medium coffee with oat milk small coffee with almond milk, 2 sugar(s)
El parámetro size no tiene valor predeterminado: es obligatorio. Los parámetros milk y sugar sí lo tienen, así que son opcionales. Así funcionan muchas bibliotecas reales de Python: unos pocos parámetros obligatorios y muchos opcionales con valores predeterminados razonables.
La trampa de los valores predeterminados mutables
Esta es una de las sorpresas más famosas de Python. Cuando usas un objeto mutable (como una lista) como valor predeterminado, ese objeto se crea una sola vez, al definir la función, y no cada vez que se llama.
Eso significa que todas las llamadas comparten la misma lista. Los cambios de una llamada pasan a la siguiente. Veámoslo en acción:
['apples'] ['apples', 'bread'] ['apples', 'bread', 'milk']
¿Te sorprende? Cada llamada debería empezar con una lista nueva, pero la lista no para de crecer. Esto pasa porque [] se crea una sola vez, cuando se define la función, y se reutiliza en cada llamada.
La solución es un patrón muy conocido de Python: usa None como valor predeterminado y crea la lista nueva dentro de la función.
['apples'] ['bread'] ['milk']
¿Qué hace *args?
A veces no sabes de antemano cuántos argumentos va a recibir una función. Quizá quieres una función que sume cualquier cantidad de números: 2, 5 o 100.
La sintaxis *args reúne todos los argumentos posicionales extra en una tupla. Luego puedes recorrerlos, acceder a ellos por índice o hacer con ellos cualquier cosa que harías con una tupla.
6 100 5
El nombre args es solo una convención. Podrías escribir *numbers, *items o *values. La magia está en el *: le dice a Python que empaquete en una tupla todos los argumentos posicionales que quedan.
<class 'tuple'>
('hello', 42, True)
Argument 0: hello
Argument 1: 42
Argument 2: TruePuedes combinar *args con parámetros normales. Los parámetros normales toman sus valores primero y luego *args recoge todo lo que sobra.
Hello, Alice! Hello, Bob! Hello, Charlie!
¿Qué hace **kwargs?
Mientras que *args reúne los argumentos posicionales extra, **kwargs reúne los argumentos con nombre extra en un diccionario. Las claves son los nombres de los argumentos y los valores son sus valores.
name: Alice age: 25 city: Paris
Igual que args, el nombre kwargs es solo una convención. Podrías escribir **info, **options o **settings. Lo que importa es el **: le dice a Python que empaquete en un diccionario los argumentos con nombre extra.
Esto es muy útil para funciones que necesitan ser flexibles. Puedes pasar cualquier dato con nombre sin cambiar la definición de la función.
Username: alice_99 email: alice@mail.com age: 25 Username: bob_42 city: London
Combinar todos los tipos de argumentos
Puedes usar parámetros normales, valores predeterminados, *args y **kwargs en la misma función. Pero el orden importa. Python exige este orden concreto:
*args**kwargsOrder from: Pizza Palace Items: margherita, garlic bread Delivery: True tip: 5 note: extra cheese
def process(*args, **kwargs):
# What does this expect?
passdef process(data, format='json',
verbose=False):
# Easy to understand
passEjercicios de práctica
¿Qué imprime este código? Escribe la salida exacta.
def power(base, exponent=2):
print(base ** exponent)
power(5)
power(2, 10)
power(exponent=3, base=4)Escribe una función llamada greet que reciba un parámetro name y un parámetro opcional greeting con el valor predeterminado 'Hello'. Debe imprimir <greeting>, <name>!. Por ejemplo, greet('Alice') imprime Hello, Alice! y greet('Bob', 'Hey') imprime Hey, Bob!.
Escribe una función llamada sum_all que use *args para aceptar cualquier cantidad de argumentos numéricos y devuelva su suma. Si no recibe ningún argumento, debe devolver 0.
Esta función debería crear una lista nueva cada vez, pero tiene el error del valor predeterminado mutable. Corrígela para que cada llamada empiece con una lista nueva.
Salida esperada:
[1]
[2]
[3]Escribe una función llamada build_profile que reciba un parámetro obligatorio name y use **kwargs para aceptar cualquier información adicional. Debe imprimir el nombre en la primera línea y luego cada par clave-valor en las líneas siguientes, con el formato key: value (con dos espacios al principio). Imprime las claves en el orden en que se pasan.
Ejemplo: build_profile('Alice', age=25, city='NYC') debe imprimir:
Alice
age: 25
city: NYCEscribe una función llamada calc que reciba una cadena operation ('add', 'multiply' o 'max') y luego cualquier cantidad de argumentos numéricos mediante *args. Debe devolver el resultado:
'add': la suma de todos los números (0 si no hay ninguno)'multiply': el producto de todos los números (1 si no hay ninguno)'max': el número más grande (0 si no hay ninguno)Ejemplos: calc('add', 1, 2, 3) devuelve 6. calc('multiply', 2, 3, 4) devuelve 24.
Refactoriza la función de abajo para que use **kwargs en lugar de parámetros individuales. La función debe aceptar name como parámetro obligatorio y todo lo demás a través de **kwargs. Imprime el nombre y luego cada dato en su propia línea con el formato key: value. La salida debe coincidir exactamente.
Original:
def show_student(name, grade, school, gpa):
print(name)
print('grade: ' + str(grade))
print('school: ' + school)
print('gpa: ' + str(gpa))Salida esperada para show_student('Alice', grade=10, school='Lincoln', gpa=3.8):
Alice
grade: 10
school: Lincoln
gpa: 3.8