Aprende leyendo en orden

Argumentos de longitud variable *args / **kwargs y múltiples valores de retorno

Aprende a recibir cualquier número de argumentos con args y *kwargs y a devolver varios valores como tupla.

En el artículo anterior sobre def, definiste funciones con un número fijo de argumentos. En el código real, sin embargo, el número de argumentos no siempre se conoce de antemano, y a veces quieres devolver más de un resultado en una sola llamada.

Python maneja esto con argumentos de longitud variable y múltiples valores de retorno. Ambos se basan directamente en lo que ya sabes sobre tuplas y dicts.

Argumentos posicionales de longitud variable *args — recolectar en una tupla

Pon un solo asterisco delante del nombre de un argumento (*args) y la función puede aceptar cualquier número de argumentos posicionales. Dentro de la función, esos argumentos están disponibles como una tupla.

El nombre args es la convención, pero técnicamente cualquier nombre descriptivo funciona — *prices, *messages, lo que se lea bien para el caso de uso.

Recolectando argumentos posicionales con *args
lado del llamadorsum_all(100, 200, 300)definicióndef sum_all(*prices):dentro de la funciónprices = (100, 200, 300)pasarrecolectar
# Acepta cualquier número de argumentos posicionales
def sum_all(*prices):
    print(prices)        # (100, 200, 300)
    print(type(prices))  # <class 'tuple'>
    return sum(prices)

print(sum_all(100, 200, 300))   # 600
print(sum_all(500))             # 500 (uno también vale)
print(sum_all())                # 0   (cero da una tupla vacía)

Combinando argumentos normales con *args

Coloca argumentos normales antes de *args y podrás mezclar un argumento inicial fijo con una cola de longitud variable. Escribir log(level, *messages) significa que el primer valor se asigna a level y todo lo demás se recolecta en una tupla llamada messages. El orden es argumentos normales → *args.

Argumentos normales combinados con *args
log("INFO", "Iniciado", "Conectado")def log(level, *messages):level = "INFO"messages =("Iniciado", "Conectado")pasarel primero al arg normalel resto a una tupla
def log(level, *messages):
    for m in messages:
        print(f"[{level}] {m}")

log("INFO", "Iniciado", "Conectado")
# [INFO] Iniciado
# [INFO] Conectado

Construye una función que acepte cualquier número de precios de productos y devuelva su total.

① Define def calc_total(*prices): y return sum(prices).

② Imprime el resultado de calc_total(300, 500) y calc_total(120, 280, 550, 400). Confirma que la misma función funciona sin importar cuántos argumentos pases.

(Una vez que se ejecute correctamente, aparecerá la explicación.)

Editor Python

Ejecutar el código para ver el resultado

Argumentos por palabra clave de longitud variable **kwargs — recolectar en un dict

Dos asteriscos (`kwargs) permiten que la función acepte cualquier argumento por palabra clave en forma de name=value. Dentro de la función, esos argumentos llegan como un dict, lo que hace que esto sea perfecto cuando las claves no se conocen de antemano**.

El nombre convencional es kwargs (abreviatura de keyword arguments).

Recolectando argumentos por palabra clave con **kwargs
lado del llamadorshow(name="Ana", age=30)definicióndef show(**info):dentro de la funcióninfo = {"name": "Ana", "age": 30}tipo: dictpasarrecolectar

Llamar a show(name="Ana", age=30) le da al receptor el dict {"name": "Ana", "age": 30}. El hecho de no tener que declarar las claves de antemano es la idea principal.

def describe_user(**info):
    print(info)            # {'name': 'Ana', 'age': 30, 'city': 'Madrid'}
    print(type(info))      # <class 'dict'>
    for key, value in info.items():
        print(f"{key}: {value}")

describe_user(name="Ana", age=30, city="Madrid")

Combinando argumentos normales con **kwargs

Pon un argumento normal antes de **kwargs y obtendrás **un valor obligatorio fijo** más **campos opcionales flexibles**. Definir def save_user(name, **info): significa que name siempre es obligatorio, mientras que campos extra como age=30 o city="Madrid" se recolectan en el dict info.

Argumentos normales combinados con **kwargs
save_user("Ana", age=30, city="Madrid")def save_user(name, **info):name = "Ana"info ={"age": 30, "city": "Madrid"}pasarel primero al arg normalel resto a un dict
def save_user(name, **info):
    print(f"name: {name}")
    for key, value in info.items():
        print(f"{key}: {value}")

save_user("Ana", age=30, city="Madrid")
# name: Ana
# age: 30
# city: Madrid

Escribe una función que tome la información del usuario como argumentos por palabra clave e imprima cada entrada en su propia línea.

① Define def show_profile(**info): y recorre con for key, value in info.items(): imprimiendo f"{key}: {value}".

② Llámala con show_profile(name="Ana", age=20, city="Barcelona").

Editor Python

Ejecutar el código para ver el resultado

Usando argumentos normales, *args y **kwargs juntos

Los tres tipos de argumentos pueden coexistir en una sola función. El orden es fijo: argumentos normales → *args → **kwargs. Escribir def register(user_id, *tags, **meta): asigna el primer valor a user_id, recolecta cualquier otro argumento posicional en la tupla tags, y recolecta cada argumento key=value en el dict meta.

def register(user_id, *tags, **meta):
    print(f"id: {user_id}")
    print(f"tags: {tags}")
    print(f"meta: {meta}")

register(1001, "admin", "beta", email="ana@example.com", active=True)
# id: 1001
# tags: ('admin', 'beta')
# meta: {'email': 'ana@example.com', 'active': True}

Escribe una función que use argumentos normales, *args y **kwargs todos a la vez.

① Define def register(user_id, *tags, **meta): e imprime tres líneas: f"id: {user_id}", f"tags: {tags}" y f"meta: {meta}".

② Llama a register(1001, "admin", "beta", email="ana@example.com", active=True) y observa cómo cada argumento aterriza en su lugar.

Editor Python

Ejecutar el código para ver el resultado

Desempaquetado del lado de la llamada — *list / **dict

Cuando pasas una lista o dict existente a una función, el hecho de poner o no * o ** delante cambia el resultado drásticamente.

Si la pasas tal cual sin * o **, la lista o dict se trata **como un solo valor que no se desempaqueta**. Recíbela a través de *args y acabarás con una tupla que contiene una lista (p. ej. ([1, 2, 3],)`) — esa es la trampa.

Con `list / dict del lado de la llamada, el contenido se expande uno por uno, así que *args / **kwargs ven la tupla (1, 2, 3) o el dict {"name": "Ana"} esperados.

Si escribes * o no cambia lo que contiene *args
lst = [1, 2, 3]f(lst)(sin *)args =([1, 2, 3],)(una lista)lst = [1, 2, 3]f(*lst)(con *)args =(1, 2, 3)(desempaquetado)queda como unose expande
def sum_all(*prices):
    return sum(prices)

prices = [120, 280, 550]

# X: pasada como una sola lista
# print(sum_all(prices))     # error (sum intenta sumar la lista misma a números)

# O: expándela con `*`
print(sum_all(*prices))       # 950 — igual que sum_all(120, 280, 550)

# La misma idea con dicts
def announce(name, city):
    print(f"{name} de {city}")

user = {"name": "Carlos", "city": "Sevilla"}
announce(**user)              # igual que announce(name="Carlos", city="Sevilla")

El desempaquetado brilla al pasar datos existentes

Cuando ya tienes los datos como una lista o dict, el desempaquetado los pasa a una función en una sola línea.

Por ejemplo, el dict user = {"name": "Carlos", "city": "Sevilla"} se convierte en announce(**user) — eso es lo mismo que escribir announce(name="Carlos", city="Sevilla"). No tienes que extraer cada clave a mano.

Toma la lista existente cart_prices = [480, 1200, 320, 980] y expándela dentro de la función calc_total de antes.

① Redefine def calc_total(*prices): devolviendo sum(prices).

② Declara cart_prices = [480, 1200, 320, 980] y haz print() del resultado de calc_total(*cart_prices).

③ Prueba print(calc_total(cart_prices)) sin el asterisco. Obtendrás un error — léelo y confirma que la lista en sí termina como el primer argumento.

Editor Python

Ejecutar el código para ver el resultado

Múltiples valores de retorno — devolver como tupla, desempaquetar al recibir

return acepta múltiples valores separados por comas, y el llamador obtiene una tupla con esos valores. Recíbelos con a, b = funcion() para desempaquetar la tupla en varias variables de una sola vez.

Esto es útil siempre que quieras devolver varios valores desde una función (mínimo y máximo, nombre de usuario y rol, bandera de éxito y mensaje, y así sucesivamente).

Los múltiples valores de retorno regresan como una tupla
def get_person():return name, age, city(name, age, city)(tupla)result = get_person()# result sigue siendo tuplaname, age, city= get_person()se expande enname, age, cityvalor realdesempaquetar
# Devuelve varios valores a la vez
def get_person():
    return "Ana", 30, "Madrid"

# Recibe como tupla
result = get_person()
print(result)            # ('Ana', 30, 'Madrid')
print(type(result))      # <class 'tuple'>

# O desempaqueta en variables individuales
name, age, city = get_person()
print(name, age, city)   # Ana 30 Madrid

# Ejemplo práctico: devuelve mín y máx juntos
def get_min_max(values):
    return min(values), max(values)

lowest, highest = get_min_max([120, 500, 300, 180])
print(f"min {lowest} / max {highest}")

Usa *rest para capturar el resto

Dada una lista de notas como return 90, 85, 78, 92, 88, escribe first, *middle, last = ... y obtendrás first=90, last=88, middle=[85, 78, 92]el primer y el último valor, con el resto recolectado en una lista. Es la herramienta adecuada cuando quieres quedarte solo con el principio y el final y agrupar todo lo que hay en medio.

Escribe una función que devuelva tanto el precio más bajo como el más alto de una lista de productos.

① Define def get_price_range(prices): y return min(prices), max(prices) para devolver dos valores.

② Prepara product_prices = [480, 1200, 320, 980, 650] y desempaqueta el resultado con lowest, highest = get_price_range(product_prices).

③ Imprime f"Más bajo: {lowest}" y f"Más alto: {highest}".

Editor Python

Ejecutar el código para ver el resultado
QUIZ

Verificación de conocimientos

Responde cada pregunta una a una.

Pregunta 1¿Qué imprime este código?
def f(*args):
return sum(args)

print(f(1, 2, 3, 4))

Pregunta 2¿Cuál es el tipo de kwargs recibido por def f(**kwargs):?

Pregunta 3Dado nums = [1, 2, 3], ¿qué llamada pasa su contenido como tres argumentos posicionales a f(a, b, c)?