Python es el lenguaje de programación más utilizado. Hoy aprenderá a utilizar una de sus características fundamentales, pero a menudo ignorada, el desempaquetado en Python.
Probablemente haya visto * y ** en el código de otros o incluso los haya utilizado sin saber realmente cuál es su propósito. Vamos a recorrer el concepto de desempaquetado y cómo utilizarlo para escribir código más pythoniano.
He aquí una lista de conceptos que encontrará útiles mientras lee este tutorial:
- Iterable: Cualquier secuencia que pueda ser iterada por un bucle paracomo conjuntos, listas, tuplas y diccionarios
- Llamable: Un objeto de Python que se puede llamar utilizando paréntesis dobles (), por ejemplo, mifunción()
- Shell: Entorno de ejecución interactivo que nos permite ejecutar código Python. Podemos llamarlo ejecutando "python" en un terminal
- Variable: Nombre simbólico que almacena un objeto y tiene una ubicación de memoria reservada.
Empecemos por la confusión más frecuente: Los asterísticos en Python son también operadores aritméticos. Un asterisco (*) se utiliza para la multiplicación, mientras que dos de ellos (**) se refieren a la exponenciación.
Podemos comprobarlo abriendo un intérprete de comandos de Python y escribiendo
>>> 3*3
9
>>> 3**3
27
Nota: Necesita tener instalado Python 3 para seguir este tutorial. Si no lo tiene instalado consulte nuestra guía de instalación de Python.
Como puede ver, estamos utilizando el asterisco después del primer número y antes del segundo. Cuando vea esto, significa que estamos utilizando los operadores aritméticos.
Por otro lado, utilizamos los asteriscos (*, **) antes de un iterable para descomprimirlo - por ejemplo:
>>> *range(1, 6),
(1, 2, 3, 4, 5)
>>> {**{'vainilla':3, 'chocolate':2}, 'fresa':2}
{'vainilla': 3, 'chocolate': 2, 'fresa': 2}
No se preocupe si no lo entiende, esto es sólo un preámbulo para desempaquetar en Python. ¡Así que siga adelante y lea todo el tutorial!
¿Qué es desempacar?
Desempaquetar es el proceso de sacar cosas - iterables como listas, tuplas y diccionarios. Piense en ello como si abriera una caja y sacara diferentes elementos como cables, auriculares o un USB.

Traducimos este mismo ejemplo a código para una mejor comprensión:
>>> mybox = ['cables', 'auriculares', 'USB']
>>> item1, item2, item3 = mybox
Como puede ver, estamos asignando los tres elementos de la lista mybox a tres variables item1, item2 , item2. Este tipo de asignación de variables es el concepto fundamental de descompresión en Python.
Si intenta obtener el valor de cada elemento, se dará cuenta de que artículo1, se refiere a "cables", artículo2, se refiere a "auriculares" y así sucesivamente.
>>> item1
'cables'
>>> item2
'auriculares'
>>> item3
'USB'
Hasta aquí, todo parece ir bien con este código, pero ¿qué pasaría si quisiéramos descomprimir una lista con más elementos en ella - manteniendo la misma cantidad de variables asignadas?
>>> newbox = ['cables', 'auriculares', 'USB', 'ratón']
>>> item1, item2, item3 = newbox
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 3)
Es probable que esperara este tipo de error. Esencialmente estamos asignando 4 elementos de lista a tres variables, ¿cómo se las arregla Python para asignar los valores correctos?
No lo hace, eso es porque obtenemos un ErrorValor con el mensaje "demasiados valores para desempaquetar". Esto ocurre porque estamos estableciendo tres variables a la izquierda, y cuatro valores (correspondientes a la lista newbox) a la derecha.
Si intenta realizar un proceso similar, pero con más variables que valores a desempaquetar, obtendrá otro ErrorValor excepto que con un mensaje ligeramente diferente:
>>> lastbox = ['cables', 'auriculares']
>>> item1, item2, item3 = lastbox
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected 3, got 2)
Nota: Hemos estado trabajando con listas pero puede utilizar esta forma de desempaquetar con cualquier iterable (listas, conjuntos, tuplas, diccionarios)
Entonces, ¿cómo superamos esta situación? ¿Hay alguna forma de desempaquetar todos los elementos de un iterable a un par de variables sin obtener errores?
Claro que la hay, y se llama operador de desempaquetado u operador asterisco (*, **). Veamos cómo utilizarlo en Python.
Cómo desempaquetar listas con el operador *
El operador asterisco (*) se utiliza para desempaquetar todos los valores de un iterable que aún no han sido asignados.
Supongamos que desea obtener el primer y el último elemento de una lista sin utilizar índices, podríamos hacerlo con el operador asterisco:
>>> primero, *no utilizado, último = [1, 2, 3, 5, 7]
>>> primero
1
>>> último
7
>>> no utilizado
[2, 3, 5]
Como puede apreciar, obtendremos todos los valores no utilizados con el operador asterisco. La forma preferida de descartar valores es utilizar una variable con guión bajo (_), que a veces se utiliza como "variable ficticia".
>>> first, *_, last = [1, 2, 3, 5, 7]
>>> _
[2, 3, 5]
Podemos seguir utilizando este truco aunque la lista sólo tenga dos elementos:
>>> primero, *_, último = [1, 2]
>>> primero
1
>>> último
2
>>> _
[]
En este caso, la variable de subrayado (variable ficticia) almacena una lista vacía para que las otras dos variables a su alrededor puedan acceder a los valores disponibles de la lista.
Solución de problemas comunes
Podemos descomprimir un elemento único de un iterable. Por ejemplo, se obtendría algo como esto
>>> *cadena = 'PythonEsElMejor'
Sin embargo, el código anterior devolverá un Error de sintaxis:
>>> *cadena = 'PythonIsTheBest'
Archivo "<stdin>", línea 1
SyntaxError: starred assignment target must be in a list or tuple
Esto porque según la especificación PEP:
Una tupla (o lista) en el lado izquierdo de una asignación simple
Si queremos desempaquetar todos los valores de un iterable a una única variable, debemos establecer una tupla, por lo que añadir una simple coma será suficiente:
>>> *cadena, = 'PythonEsElMejor'
>>> cadena
['P', 'y', 't', 'h', 'o', 'n', 'I', 's', 'T', 'h', 'e', 'B', 'e', 's', 't']
Otro ejemplo sería utilizar la función rango, que devuelve una secuencia de números.
>>> *números, = rango(5)
>>> números
[0, 1, 2, 3, 4]
Ahora que ya sabe cómo desempaquetar listas y tuplas con un asterisco, es hora de entrar en el desempaquetado de diccionarios.
Cómo desempaquetar diccionarios con el operador **
Mientras que el asterisco simple se utiliza para descomprimir listas y tuplas, el asterisco doble (**) se utiliza para descomprimir diccionarios.
Por desgracia, no podemos descomprimir un diccionario en una única variable como hemos estado haciendo con tuplas y listas. Esto significa que lo siguiente arrojará un error:
>>> **saludos, = {'hola': 'HELLO', 'adiós':'BYE'}
...
SyntaxError: sintaxis inválida
Sin embargo, podemos utilizar el operador ** dentro de callables y otros diccionarios. Por ejemplo, si queremos crear un diccionario fusionado, hecho a partir de otros diccionarios, podríamos utilizar el código siguiente:
>>> comida = {'pescado':3, 'carne':5, 'pasta':9}
>>> colores = {'rojo': 'intensidad', 'amarillo':'felicidad'}
>>> diccionario_fusionado = {**comida, **colores}
>>> diccionario_fusionado
{'pescado': 3, 'carne': 5, 'pasta': 9, 'rojo': 'intensidad', 'amarillo': 'felicidad'}
Esta es una forma bastante corta de crear diccionarios compuestos, sin embargo, este no es el enfoque principal de desempaquetar en Python.
Veamos cómo podemos utilizar el desempaquetado con callables
Empaquetado en funciones: args y kwargs
Probablemente haya visto antes args y kwargs implementados en clases o funciones. Veamos por qué necesitamos utilizarlos junto con los callables.
Empaquetamiento con el operador * (args)
Supongamos que tenemos una función que calcula el producto de dos números.
>>> def producto(n1, n2):
... devuelve n1 * n2
...
>>> números = [12, 1]
>>> producto(*números)
12
Como puede ver, estamos descomprimiendo la lista números en la función, por lo que en realidad estamos ejecutando lo siguiente:
>>> producto(12, 1)
12
Hasta aquí todo funciona bien, pero ¿qué pasaría si quisiéramos pasar una lista más larga? Seguramente se producirá un error porque la función está recibiendo más argumentos de los que es capaz de gestionar.
>>> números = [12, 1, 3, 4]
>>> producto(*números)
...
TypeError: producto() toma 2 argumentos posicionales pero se dieron 4
Podemos solucionar todo esto simplemente empaquetando la lista directamente en la función, lo que crea un iterable dentro de ella y nos permite pasar cualquier número de argumentos a la función.
>>> def product(*args):
... result = 1
... for i in args:
... result *= i
... return result
...
>>> product(*numbers)
144
Aquí estamos tratando el parámetro args como un iterable, recorriendo sus elementos y devolviendo el producto de todos los números. Observe cómo el número inicial del resultado debe ser uno porque si empezamos con cero, la función siempre devolverá cero.
Nota: args es sólo una convención, puede utilizar cualquier otro nombre de parámetro
También podríamos pasar números arbitrarios a la función sin utilizar una lista, al igual que con la función imprimir incorporada.
>>> product(5, 5, 5)
125
>>> print(5, 5, 5)
5 5 5
Por último, obtengamos el tipo de objeto de los args de una función.
>>> def prueba_tipo(*args):
... print(tipo(args))
... print(args)
...
>>> prueba_tipo(1, 2, 4, 'una cadena')
<clase 'tupla'>
(1, 2, 4, 'una cadena')
Como se observa en el código anterior, el tipo de args será siempre tupla, y su contenido serán todos los argumentos sin clave pasados a la función.
Empaquetado con el operador ** (kwargs)
Como vimos anteriormente, el operador ** se utiliza exclusivamente para diccionarios. Esto significa que con este operador podemos pasar pares clave-valor a la función como parámetro.
Creemos una función hacer_persona, que recibe un argumento posicional "nombre", y una cantidad indefinida de argumentos clave.
>>> def hacer_persona(nombre, **kwargs):
... result = nombre ': '
... for clave, valor in kwargs.items():
... result = f'{clave} = {valor}, '
... return resultado
...
>>> make_person('Melissa', id=12112, location='london', net_worth=12000)
'Melissa: id = 12112, location = london, net_worth = 12000, '
Como puede ver, la sentencia **kwargs convierte todos los argumentos con palabras clave en un diccionario, que podemos iterar dentro de la función.
Nota: kwargs es sólo una convención puede nombrar este parámetro con lo que quiera
Podemos comprobar el tipo de los kwargs del mismo modo que hicimos con los args:
>>> def test_kwargs(**kwargs):
... print(type(kwargs))
... print(kwargs)
...
>>> test_kwargs(random=12, parameters=21)
<class 'dict'>
{'random': 12, 'parameters': 21}
La variable interna kwargs resulta ser siempre un diccionario, que almacena los pares clave-valor pasados a la función.
Por último, hagamos uso de args y kwargs en la misma función:
>>> def mi_funcion_final(*args, **kwargs):
... print('Tipo args: ', type(args))
... print('args: ', args)
... print('Tipo kwargs: ', type(kwargs))
... print('kwargs: ', kwargs)
...
>>> mi_funcion_final('Python', 'El', 'Mejor', lenguaje='Python', usuarios='Mucho')
Tipo args: <clase 'tuple'>
args: ('Python', 'The', 'Best')
Tipo kwargs: <class 'dict'>
kwargs: {'language': 'Python', 'users': 'A lot'}
Conclusión
Los operadores de desempaquetado son realmente útiles en las tareas cotidianas, ahora ya sabe cómo utilizarlos tanto en sentencias individuales como en parámetros de funciones.
En este tutorial ha aprendido :
- Se utiliza * para tuplas y listas y ** para diccionarios
- Puede utilizar operadores de descompresión en funciones y constructores de clases
- se utilizanargs para pasar parámetros sin palabras clave a las funciones
- kwargs se utilizan para pasar parámetros con palabras clave a las funciones.
A continuación, puede aprender a utilizar los operadores no iguales de Python.