Los operadores * y ** en las llamadas a funciones operan de manera opuesta a como lo hacen en sus definiciones. Veamos un ejemplo con la función sum():
def sum(*numbers):
result = 0
for num in numbers:
result += num
return result
Llamemos a sum() usando el operador * para expandir una lista de argumentos:
numbers = [1, 7, 4]
sum(*numbers) # 12
Aquí, el operador * desempaqueta la lista y pasa sus elementos como argumentos individuales. Es decir, el código se convierte en:
sum(numbers[0], numbers[1], numbers[2])
# sum(1, 7, 4)
Como en la definición de funciones, el operador * puede combinarse con argumentos posicionales:
numbers = [1, 7, 4]
sum(8, *numbers) # 20
sum(8, 10, *numbers) # 30
sum(8, 10, 70, *numbers) # 100
A diferencia de su uso en la definición de funciones, en una llamada el operador * no tiene que ir al final. Se puede colocar en cualquier posición:
numbers = [1, 7, 4]
sum(8, 10, *numbers) # 30
sum(8, *numbers, 10) # 30
sum(*numbers, 8, 10) # 30
Incluso se pueden usar varios operadores * en una misma llamada:
numbers1 = [1, 7, 4]
numbers2 = [5, 5]
# sum(1, 7, 4, 5, 5)
sum(*numbers1, *numbers2) # 22
# sum(5, 5, 1, 7, 4)
sum(*numbers2, *numbers1) # 22
# sum(8, 1, 7, 4, 10, 5, 5)
sum(8, *numbers1, 10, *numbers2) # 40
Desempaquetado de argumentos con **
El operador ** funciona de manera similar, pero para argumentos con nombre (diccionarios):
def func(**kwargs):
for key, value in kwargs.items():
print('key = ', key)
print('value = ', value)
d = {'a': 42, 'b': 'python'}
# Desempaquetamos el diccionario
func(**d)
# key = a
# value = 42
# key = b
# value = python
Si olvidamos el ** al llamar la función, obtendremos un error, porque la función espera argumentos nombrados, no un diccionario:
d = {'a': 42, 'b': 'python'}
func(d)
# ❌ TypeError: func() takes 0 positional arguments but 1 was given
El operador ** desempaqueta el diccionario y convierte sus pares clave-valor en argumentos nombrados (a=42, b='python'). Luego, estos se agrupan nuevamente en el diccionario kwargs dentro de la función.
Un uso común es en funciones de configuración con opciones ilimitadas:
def get_config(**options):
default_options = {'case': 'lower', 'output': 'console'}
# Combina opciones predeterminadas con las nuevas
return default_options | options
get_config() # {'case': 'lower', 'output': 'console'}
get_config(**{'case': 'upper'}) # {'case': 'upper', 'output': 'console'}
get_config(**{'case': 'upper', 'code': 'utf-8'})
# {'case': 'upper', 'output': 'console', 'code': 'utf-8'}
Resumen
Los operadores * y ** sirven para empaquetar y desempaquetar argumentos en funciones. Para evitar confusiones:
- Empaquetado
*: Se usa en definiciones de funciones para agrupar argumentos restantes. - Desempaquetado
**: Se usa en llamadas de funciones para expandir listas/diccionarios en argumentos individuales.
Combinándolos, podemos hacer funciones muy flexibles.
Para acceder completo a curso necesitas un plan básico
El plan básico te dará acceso completo a todos los cursos, ejercicios y lecciones de Códica, proyectos y acceso de por vida a la teoría de las lecciones completadas. La suscripción se puede cancelar en cualquier momento.