¿Cómo usar los operadores de desempaquetado (*, **) en Python?

Python es el lenguaje de programación más utilizado. Hoy aprenderá a usar una de sus funciones principales, pero a menudo ignorada, desempaquetar en Python.

Probablemente hayas visto * y ** en el código de otros o incluso los hayas usado sin saber realmente cuál es su propósito. Analizaremos el concepto de desempaquetar y cómo usarlo para escribir más código Pythonic.

Aquí hay una lista de conceptos que encontrará útiles mientras lee este tutorial:

Iterable: Cualquier secuencia que puede ser iterada por un en buclecomo conjuntos, listas, tuplas y diccionarios
Llamable: un objeto de Python que se puede llamar usando paréntesis doble (), por ejemplo, mifuncion()
Cascarón: Entorno de tiempo de ejecución interactivo que nos permite ejecutar el código de Python. Podemos llamarlo ejecutando “python” en una terminal
Variable: Nombre simbólico que almacena un objeto y tiene una ubicación de memoria reservada.

Comencemos con la confusión más frecuente: los asterísticos en Python también son operadores aritméticos. un asterisco

se utiliza para la multiplicación, mientras que dos de ellos (**) se refieren a la exponenciación.

>>> 3*3
9
>>> 3**3
27

Podemos probar eso abriendo un shell de Python y escribiendo:

Nota: Debe tener Python 3 instalado para seguir este tutorial. Si no lo tiene instalado, consulte nuestra guía de instalación de Python.

Como puede ver, estamos usando el asterisco después del primer número y antes del segundo. Cuando vea esto, significa que estamos usando los operadores aritméticos.

>>> *range(1, 6),
(1, 2, 3, 4, 5)
>>> {**{'vanilla':3, 'chocolate':2}, 'strawberry':2}
{'vanilla': 3, 'chocolate': 2, 'strawberry': 2}

Por otro lado, usamos los asteriscos (*, **) antes de un iterable para descomprimirlo, por ejemplo:

No se preocupe si no lo entiende, esto es solo un preámbulo para desempaquetar en Python. ¡Así que adelante y lee todo el tutorial!

¿Qué está desempacando?

Desempaquetar es el proceso de sacar cosas, iterables como listas, tuplas y diccionarios.  Piense en ello como abrir una caja y sacar diferentes elementos como cables, auriculares o un USB.Imagen de la caja de desembalaje

Desempacar en Python es similar a desempacar una caja en la vida real.

>>> mybox = ['cables', 'headphones', 'USB']
>>> item1, item2, item3 = mybox

Traduzcamos este mismo ejemplo a código para una mejor comprensión: Como puede ver, estamos asignando los tres elementos dentro de la mi caja lista de tres variablesartículo1, artículo2, artículo2

. Este tipo de asignación de variables es el concepto fundamental del desempaquetado en Python. Si intenta obtener el valor de cada artículo, notará queObjeto 1 se refiere a “cables”,artículo2

>>> item1
'cables'
>>> item2
'headphones'
>>> item3
'USB'

se refiere a “auriculares”, etc.

>>> newbox = ['cables', 'headphones', 'USB', 'mouse']
>>> item1, item2, item3 = newbox
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 3)

Hasta aquí, todo parece estar bien con este código, pero ¿qué pasaría si quisiéramos desempaquetar una lista con más elementos, manteniendo la misma cantidad de variables asignadas?

Probablemente esperabas este tipo de error. Básicamente, estamos asignando 4 elementos de la lista a tres variables, ¿cómo logra Python asignar los valores correctos? No lo hace, eso es porque recibimos un ValueError con el mensaje “demasiados valores para desempaquetar”. Esto está sucediendo porque estamos configurando Tres variables a la izquierda, y cuatro

valores (correspondientes a la lista newbox) a la derecha. Si intenta hacer un proceso similar, pero con más variables que valores para desempaquetar, obtendrá otro ValorError

>>> lastbox = ['cables', 'headphones']
>>> 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)

excepto que con un mensaje ligeramente diferente:

Nota: hemos estado trabajando con listas, pero puede usar 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 ningún error?

Claro que lo hay, y se llama operador de desempaquetado u operador de asterisco (*, **). Veamos cómo usarlo en Python.

Cómo descomprimir listas con el operador *

El operador asterisco

>>> first, *unused, last = [1, 2, 3, 5, 7]
>>> first
1
>>> last
7
>>> unused
[2, 3, 5]

se utiliza para desempaquetar todos los valores de un iterable que aún no se han asignado.

>>> first, *_, last = [1, 2, 3, 5, 7]
>>> _
[2, 3, 5]

Supongamos que desea obtener el primer y último elemento de una lista sin usar índices, podríamos hacerlo con el operador asterisco:

>>> first, *_, last = [1, 2]
>>> first
1
>>> last
2
>>> _
[]

Como puede apreciar, obtenemos todos los valores no utilizados con el operador asterisco. La forma preferida de descartar valores es usar una variable de subrayado (_), que a veces se usa como una “variable ficticia”.

Todavía podemos usar este truco incluso si la lista solo tiene dos elementos:

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.

>>> *string = 'PythonIsTheBest'

Solución de problemas comunes Podemos desempaquetar un elemento único de un iterable. Por ejemplo, se te ocurriría algo como esto:Sin embargo, el código anterior devolverá un

>>> *string = 'PythonIsTheBest'
  File "<stdin>", line 1
SyntaxError: starred assignment target must be in a list or tuple

Error de sintaxis

:

>>> *string, = 'PythonIsTheBest'
>>> string
['P', 'y', 't', 'h', 'o', 'n', 'I', 's', 'T', 'h', 'e', 'B', 'e', 's', 't']

Esto porque de acuerdo a la especificación PEP: Si queremos desempaquetar todos los valores de un iterable a una sola variable, debemos configurar una tupla, por lo tanto, agregar una coma simple será suficiente: Otro ejemplo sería usar el

>>> *numbers, = range(5)
>>> numbers
[0, 1, 2, 3, 4]

rango

función, que devuelve una secuencia de números.

Ahora que sabe cómo desempaquetar listas y tuplas con un asterisco, es hora de comenzar a desempaquetar diccionarios.

Cómo desempaquetar diccionarios con operador **

>>> **greetings, = {'hello': 'HELLO', 'bye':'BYE'} 
...
SyntaxError: invalid syntax

Mientras que un solo asterisco se usa para desempaquetar listas y tuplas, el doble asterisco (**) se usa para desempaquetar diccionarios.

>>> food = {'fish':3, 'meat':5, 'pasta':9} 
>>> colors = {'red': 'intensity', 'yellow':'happiness'}
>>> merged_dict = {**food, **colors}
>>> merged_dict
{'fish': 3, 'meat': 5, 'pasta': 9, 'red': 'intensity', 'yellow': 'happiness'}

Desafortunadamente, no podemos descomprimir un diccionario en una sola variable como lo hemos estado haciendo con tuplas y listas. Eso significa que lo siguiente arrojará un error:

Sin embargo, podemos usar el operador ** dentro de callables y otros diccionarios. Por ejemplo, si queremos crear un diccionario fusionado, hecho a partir de otros diccionarios, podríamos usar el siguiente código:

Esta es una forma bastante corta de crear diccionarios compuestos, sin embargo, este no es el enfoque principal para desempaquetar en Python.

Veamos cómo podemos usar el desempaquetado con callables

Empaquetado en Funciones: args y kwargs

Probablemente haya visto args y kwargs antes implementados en clases o funciones. Veamos por qué necesitamos usarlos junto con callables.

>>> def product(n1, n2):
...     return n1 * n2
... 
>>> numbers = [12, 1]
>>> product(*numbers)
12

Empaquetado con el operador * (args) Supongamos que tenemos una función que calcula el producto de dos números. Como puede ver, estamos desempacando la lista

>>> product(12, 1)
12

números

>>> numbers = [12, 1, 3, 4]
>>> product(*numbers)
...
TypeError: product() takes 2 positional arguments but 4 were given

a la función, por lo que en realidad estamos ejecutando lo siguiente: Hasta aquí, todo funciona bien, pero ¿y si quisiéramos pasar una lista más larga? Ciertamente generará un error porque la función está recibiendo más argumentos de los que es capaz de administrar. Podemos resolver todo esto con solo

>>> def product(*args):
...     result = 1
...     for i in args:
...             result *= i
...     return result
...
>>> product(*numbers)
144

embalaje la lista directamente en la función, lo que crea un iterable dentro de ella y nos permite pasar cualquier cantidad de argumentos a la función. Aquí estamos tratando el

argumentos

parámetro como 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 comenzamos con cero, la función siempre devolverá cero.

>>> product(5, 5, 5)
125
>>> print(5, 5, 5)
5 5 5

Nota: args es solo una convención, puede usar cualquier otro nombre de parámetro También podríamos pasar números arbitrarios a la función sin usar una lista, al igual que con la función de impresión incorporada. Finalmente, obtengamos el tipo de objeto del

>>> def test_type(*args):
...     print(type(args))
...     print(args)
... 
>>> test_type(1, 2, 4, 'a string')
<class 'tuple'>
(1, 2, 4, 'a string')

argumentos de una función Como se señaló en el código anterior, el tipo de argumentosserá siempre

tupla

y su contenido serán todos los argumentos sin palabras clave pasados ​​a la función.

Embalaje con el operador ** (kwargs) Como vimos anteriormente, el operador ** se usa exclusivamente para diccionarios. Esto significa que con este operador podemos pasar pares clave-valor a la función como parámetro.Vamos a crear una función

>>> def make_person(name, **kwargs):
...     result = name + ': '
...     for key, value in kwargs.items():
...             result += f'{key} = {value}, '
...     return result
... 
>>> make_person('Melissa', id=12112, location='london', net_worth=12000)
'Melissa: id = 12112, location = london, net_worth = 12000, '

hacer_persona que recibe un argumento posicional “nombre” y una cantidad indefinida de argumentos con palabras clave. Como puedes ver, el

**kwargs

La declaración convierte todos los argumentos con palabras clave en un diccionario, que podemos iterar dentro de la función. Nota: kwargs es solo una convención, puedes nombrar este parámetro con lo que quieras Podemos comprobar el tipo de kwargsde la misma manera que hicimos con

>>> def test_kwargs(**kwargs):
...     print(type(kwargs))
...     print(kwargs)
... 
>>> test_kwargs(random=12, parameters=21)
<class 'dict'>
{'random': 12, 'parameters': 21}

argumentos : los

kwargs La variable interna siempre se convierte en un diccionario, que almacena los pares clave-valor pasados ​​a la función. Finalmente, hagamos uso de argumentos y

>>> def my_final_function(*args, **kwargs):
...     print('Type args: ', type(args))
...     print('args: ', args)
...     print('Type kwargs: ', type(kwargs))
...     print('kwargs: ', kwargs)
... 
>>> my_final_function('Python', 'The', 'Best', language='Python', users='A lot')
Type args:  <class 'tuple'>
args:  ('Python', 'The', 'Best')
Type kwargs:  <class 'dict'>
kwargs:  {'language': 'Python', 'users': 'A lot'}

kwargs

en la misma función:

Conclusión

Los operadores de desempaquetado son realmente útiles en las tareas del día a día, ahora ya sabes cómo usarlos tanto en declaraciones individuales como en parámetros de funciones.
En este tutorial aprendiste: Usa * para tuplas y listas y ** para diccionarios Puede usar operadores de desempaquetado en constructores de funciones y clases
argumentos se utilizan para pasar parámetros sin palabras clave a funcioneskwargsse utilizan para pasar parámetros con palabras clave a funciones.

Publicaciones relacionadas

Botón volver arriba