Búsqueda de sitios web

Comprensiones del diccionario Python: cómo y cuándo usarlas


La comprensión de diccionarios es una forma concisa y rápida de crear, transformar y filtrar diccionarios en Python. Pueden mejorar significativamente la concisión y legibilidad de su código en comparación con el uso de bucles for regulares para procesar sus diccionarios.

Comprender las comprensiones de diccionarios es crucial para usted como desarrollador de Python porque son una herramienta Pythonic para la manipulación de diccionarios y pueden ser una valiosa adición a su conjunto de herramientas de programación.

En este tutorial, aprenderá cómo:

  • Crear diccionarios utilizando la comprensión del diccionario
  • Transformar diccionarios existentes con comprensiones
  • Filtrar pares clave-valor de diccionarios usando condicionales
  • Decidir cuándo utilizar las comprensiones del diccionario

Para aprovechar al máximo este tutorial, debe estar familiarizado con los conceptos básicos de Python, como los bucles for, los iterables y los diccionarios, así como con las listas por comprensión.

Crear y transformar diccionarios en Python

En la programación Python, a menudo necesitarás crear, completar y transformar diccionarios. Para hacer esto, puede usar literales de diccionario, el constructor dict() y bucles for. En las siguientes secciones, echará un vistazo rápido a cómo utilizar estas herramientas. También aprenderá sobre la comprensión de diccionarios, que es una forma poderosa de manipular diccionarios en Python.

Crear diccionarios con literales y dict()

Para crear nuevos diccionarios, puede utilizar literales. Un literal de diccionario es una serie de pares clave-valor encerrados entre llaves. La sintaxis de un literal de diccionario se muestra a continuación:

{key_1: value_1, key_2: value_2,..., key_N: value_N}

Las claves deben ser objetos hash y normalmente son cadenas. Los valores pueden ser cualquier objeto de Python, incluidos otros diccionarios. Aquí hay un ejemplo rápido de un diccionario:

>>> likes = {"color": "blue", "fruit": "apple", "pet": "dog"}
>>> likes
{'color': 'blue', 'fruit': 'apple', 'pet': 'dog'}

>>> likes["hobby"] = "guitar"
>>> likes
{'color': 'blue', 'fruit': 'apple', 'pet': 'dog', 'hobby': 'guitar'}

En este ejemplo, creará pares clave-valor de diccionario que describen cosas que a la gente suele gustarle. Las claves y valores de su diccionario son objetos de cadena. Puede agregar nuevos pares al diccionario usando la sintaxis dict[key]=value.

También puedes crear nuevos diccionarios usando el constructor dict():

>>> dict(apple=0.40, orange=0.35, banana=0.25)
{'apple': 0.4, 'orange': 0.35, 'banana': 0.25}

En este ejemplo, creará un nuevo diccionario usando dict() con argumentos de palabras clave. En este caso, las claves son cadenas y los valores son números de punto flotante. Es importante tener en cuenta que el constructor dict() solo es adecuado para aquellos casos en los que las claves del diccionario pueden ser cadenas que son identificadores válidos de Python.

Uso de bucles for para completar diccionarios

A veces, es necesario comenzar con un diccionario vacío y completarlo dinámicamente con pares clave-valor. Para hacer esto, puedes usar un bucle for. Por ejemplo, supongamos que desea crear un diccionario en el que las claves sean números enteros y los valores sean potencias de 2.

Así es como puedes hacer esto con un bucle for:

>>> powers_of_two = {}

>>> for integer in range(1, 10):
...     powers_of_two[integer] = 2**integer
...

>>> powers_of_two
{1: 2, 2: 4, 3: 8, 4: 16, 5: 32, 6: 64, 7: 128, 8: 256, 9: 512}

En este ejemplo, creará un diccionario vacío utilizando un par de llaves vacías. Luego, ejecuta un bucle sobre un rango de números enteros desde 1 hasta 9. Dentro del ciclo, completa el diccionario con números enteros como claves y potencias de dos como valores.

El bucle en este ejemplo es legible y claro. Sin embargo, también puede utilizar la comprensión del diccionario para crear y completar un diccionario como el que se muestra arriba.

Introducción a las comprensiones del diccionario

Las comprensiones de diccionarios le permiten crear diccionarios con un bucle for de una línea. Si está familiarizado con la comprensión de listas, comprenderá rápidamente la comprensión del diccionario. Ambas construcciones tienen una sintaxis similar. La principal diferencia es que las comprensiones del diccionario utilizan llaves en lugar de corchetes. Además, la expresión de comprensión debe incluir una clave y un valor separados por dos puntos.

Aquí está la sintaxis para la comprensión de un diccionario:

{key: value for member in iterable [if condition]}

La comprensión de un diccionario devuelve un nuevo diccionario. Para construir este diccionario, calcula los pares clave-valor a partir de los elementos de un iterable de entrada. Tenga en cuenta que la sintaxis incluye un condicional opcional al final, que puede utilizar para filtrar diccionarios existentes.

La sintaxis de comprensión incluye cuatro elementos:

  1. Corchetes: Las llaves ({}) se utilizan para la comprensión del diccionario.
  2. La expresión de comprensión: Una expresión que proporciona un valor en cada iteración. En comprensión de diccionario, la expresión debe proporcionar la clave y su valor correspondiente, clave:valor. Ambos elementos pueden ser expresiones.
  3. El miembro actual: Este es el elemento o valor actual en el iterable.
  4. El iterable: Puede ser cualquier objeto iterable de Python, incluida una lista, tupla, conjunto, generador o similar.

El siguiente código muestra cómo puedes construir el diccionario power_of_two usando una comprensión:

>>> power_of_two = {integer: 2**integer for integer in range(1, 10)}

>>> power_of_two
{1: 2, 2: 4, 3: 8, 4: 16, 5: 32, 6: 64, 7: 128, 8: 256, 9: 512}

En este ejemplo, integer: 2**integer es la expresión de comprensión, integer es el miembro actual y range(1, 10) es el iterable.

Aquí hay un diagrama que ilustra el proceso de convertir su bucle de la sección anterior en el equivalente de comprensión del diccionario:

Como puede ver, con un par de movimientos y la adición de las llaves adjuntas, su comprensión está completa.

Las comprensiones también pueden tener más de una cláusula for. Cuando lo hacen, el for más a la izquierda itera sobre la colección externa, el siguiente for de izquierda a derecha itera sobre el primer nivel de anidamiento, y así sucesivamente.

Para ilustrar, digamos que tiene una lista de listas. Cada lista anidada contiene números. Quiere crear un diccionario que asigne números a sus valores cuadrados. Puede utilizar una comprensión con dos cláusulas for como se muestra a continuación:

>>> matrix = [
...     [9, 3, 8, 3],
...     [4, 5, 2, 8],
...     [6, 4, 3, 1],
...     [1, 0, 4, 5],
... ]

>>> {value: value**2 for row in matrix for value in row}
{9: 81, 3: 9, 8: 64, 4: 16, 5: 25, 2: 4, 6: 36, 1: 1, 0: 0}

En este ejemplo, el primer bucle for itera sobre las filas de su matriz. El segundo bucle for itera sobre el número de cada fila. Como resultado, obtienes un diccionario que asigna números a sus valores cuadrados. Aunque esta sintaxis funciona, puede dificultar la lectura y la comprensión de su comprensión.

Es importante tener en cuenta que en este ejemplo, en lugar de tener 16 pares clave-valor, terminarás con solo nueve. Esto se debe a que las claves del diccionario son únicas. Cuando la clave se duplica, el nuevo valor anula el anterior. En este ejemplo, este comportamiento no causa problemas porque los valores siempre serán el cuadrado de sus claves correspondientes.

Aprovechando la comprensión del diccionario en Python

Con la comprensión del diccionario, puede crear nuevos diccionarios, transformar los existentes e incluso filtrar pares clave-valor. En las siguientes secciones, aprenderá cómo utilizar la comprensión del diccionario para abordar todos estos casos de uso. Para comenzar, comenzará aprendiendo cómo crear nuevos diccionarios a partir de iterables existentes.

Crear diccionarios a partir de iterables

A veces, tiene un iterable de datos y desea crear un diccionario utilizando los elementos de datos para generar las claves y los valores, y al mismo tiempo aplicar alguna transformación a los datos originales. Para un ejemplo rápido, digamos que tiene una lista de frutas y desea crear un diccionario donde las claves son los nombres de las frutas que se muestran en mayúsculas y los valores representan el número de letras en cada nombre:

>>> fruits = ["apple", "banana", "cherry"]

>>> {fruit.upper(): len(fruit) for fruit in fruits}
{'APPLE': 5, 'BANANA': 6, 'CHERRY': 6}

En este ejemplo, aplica transformaciones para generar las claves y los valores. En la programación del mundo real, es posible que a menudo necesites aplicar transformaciones para generar los valores o las claves.

Considere el siguiente ejemplo que crea un diccionario con letras minúsculas como claves y sus puntos de código Unicode como valores:

>>> from string import ascii_lowercase

>>> {letter: ord(letter) for letter in ascii_lowercase}
{
    'a': 97,
    'b': 98,
    'c': 99,
    'd': 100,
    'e': 101,
    ...
    'z': 122,
}

En este ejemplo, genera los valores del diccionario ejecutando una transformación en los elementos proporcionados. Utilice los elementos de datos directamente para proporcionar las claves.

A veces, tiene dos secuencias de datos y desea asignar cada elemento de la primera secuencia al elemento correspondiente de la segunda. En este caso, puede utilizar el siguiente código:

>>> parts = [
...     "CPU",
...     "GPU",
...     "Motherboard",
...     "RAM",
...     "SSD",
...     "Power Supply",
...     "Case",
...     "Cooling Fan"
... ]

>>> stocks = [15, 8, 12, 30, 25, 10, 5, 20]

>>> {part: stock for part, stock in zip(parts, stocks)}
{
    'CPU': 15,
    'GPU': 8,
    'Motherboard': 12,
    'RAM': 30,
    'SSD': 25,
    'Power Supply': 10,
    'Case': 5,
    'Cooling Fan': 20
}

En este ejemplo, utiliza la función incorporada zip() para crear pares de elementos. Esta función toma dos o más iterables como argumentos y produce tuplas de elementos al obtener un elemento de cada iterable.

En la práctica, cuando necesite crear un diccionario a partir de dos secuencias sin aplicar ninguna transformación en los elementos de datos, puede utilizar el siguiente código en lugar de una comprensión:

>>> dict(zip(parts, stocks))
{
    'CPU': 15,
    'GPU': 8,
    'Motherboard': 12,
    'RAM': 30,
    'SSD': 25,
    'Power Supply': 10,
    'Case': 5,
    'Cooling Fan': 20
}

Esta forma de crear un diccionario a partir de dos secuencias es bastante pitónica y sencilla. No necesitas comprensión. Sin embargo, si necesita transformar los datos de alguna manera, se beneficiaría utilizando una comprensión.

Por ejemplo, digamos que tiene una tercera lista que contiene los precios de cada pieza de computadora. Quiere crear un diccionario que contenga las piezas como claves y sus costos como valores. En esta situación, no puedes utilizar el truco anterior. Necesitas usar una comprensión:

>>> part_costs = [250, 500, 150, 80, 100, 120, 70, 25]

>>> {
...     part: stock * cost
...     for part, stock, cost in zip(parts, stocks, part_costs)
... }
{
    'CPU': 3750,
    'GPU': 4000,
    'Motherboard': 1800,
    'RAM': 2400,
    'SSD': 2500,
    'Power Supply': 1200,
    'Case': 350,
    'Cooling Fan': 500,
}

En este ejemplo, usar zip() combinado con dict() no proporciona una solución adecuada para crear el diccionario porque es necesario calcular los valores. Aquí es cuando la comprensión resulta útil, ya que permite manejar el cálculo de valores.

Transformar los diccionarios existentes

También puede utilizar comprensiones para transformar las claves o valores de diccionarios existentes. Un ejemplo típico es cuando necesita intercambiar claves y valores.

Por ejemplo, supongamos que tiene un diccionario que contiene piezas de computadora que se asignan a códigos de pieza y desea una configuración opuesta. En esta situación, puede utilizar un diccionario de comprensión para intercambiar las claves y los valores:

>>> parts = {
...     "CPU": 10021,
...     "GPU": 10022,
...     "Motherboard": 10023,
...     "RAM": 10024,
...     "SSD": 10025,
...     "Power Supply": 10027,
...     "Case": 10026,
...     "Cooling Fan": 10025,
... }

>>> {value: key for key, value in parts.items()}
{
    10021: 'CPU',
    10022: 'GPU',
    10023: 'Motherboard',
    10024: 'RAM',
    10025: 'Cooling Fan',
    10027: 'Power Supply',
    10026: 'Case'
}

En esta comprensión, se utiliza el método .items() en el diccionario parts para acceder a los pares clave-valor. Luego, tienes dos variables de bucle, una para las claves y otra para los valores. En la expresión de comprensión, intercambias las claves y los valores.

Puede obtener el mismo resultado utilizando el siguiente código que combina dict() y zip() con .values() y . .keys() métodos de diccionario:

>>> dict(zip(parts.values(), parts.keys()))
{
    10021: 'CPU',
    10022: 'GPU',
    10023: 'Motherboard',
    10024: 'RAM',
    10025: 'Cooling Fan',
    10027: 'Power Supply',
    10026: 'Case'
}

En este ejemplo, utiliza una combinación de llamadas a funciones y métodos en lugar de una comprensión. El resultado es el mismo que con una comprensión.

Como otro ejemplo, digamos que tienes un diccionario de frutas y sus precios, y necesitas reducir los precios en un 5%. Puedes hacer esto con una comprensión:

>>> fruits = {
...     "apple": 1.00,
...     "banana": 0.50,
...     "cherry": 2.00,
... }

>>> {fruit: round(price * 0.95, 2) for fruit, price in fruits.items()}
{'apple': 0.95, 'banana': 0.48, 'cherry': 1.90}

En este ejemplo, transforma los valores del diccionario original. Ahora tienes un nuevo diccionario con precios un 5% más bajos.

Puede aplicar la transformación solo a las claves, o tanto a los valores como a las claves, según lo que necesite.

Filtrar elementos de diccionarios

Las comprensiones de diccionarios también le permiten utilizar un condicional al final de su sintaxis. Este condicional le permitirá crear diccionarios filtrando los datos existentes. Puede utilizar la sintaxis condicional tanto con claves como con valores.

A continuación se muestra un ejemplo que filtra un diccionario de números por sus valores para crear un diccionario de números pares:

>>> numbers = {"one": 1, "two": 2, "three": 3, "four": 4, "five": 5}

>>> {key: value for key, value in numbers.items() if value % 2 == 0}
{'two': 2, 'four': 4}

El condicional al final de la comprensión filtra los números impares del diccionario original. Como resultado, obtienes un diccionario de números pares.

Para aprender cómo filtrar un diccionario por claves, digamos que tiene un diccionario que asigna códigos postales a ciudades y necesita filtrar el diccionario para obtener las ciudades en un rango de códigos postales:

>>> codes = {
...     "1001": "Townsville",
...     "1002": "Lakeview",
...     "1003": "Mountainview",
...     "1101": "Riverside",
...     "1102": "Hilltop",
...     "1201": "Greenfield",
...     "1202": "Sunnydale",
...     "1301": "Meadowbrook",
...     "1302": "Creekwood"
... }

>>> {code: town for code, town in codes.items() if "1100" <= code <= "1300"}
{
    '1101': 'Riverside',
    '1102': 'Hilltop',
    '1201': 'Greenfield',
    '1202': 'Sunnydale'
}

En este ejemplo, la condición verifica si el código postal actual está entre 1100 y 1300. Esta condición filtra el diccionario original y genera uno nuevo con las ciudades en el rango de códigos objetivo.

Decidir cuándo utilizar las comprensiones del diccionario

Al decidir si utilizar un diccionario de comprensión en lugar de bucles regulares o una combinación de llamadas a funciones, debe considerar los siguientes factores:

  • Concisión: la comprensión del diccionario reduce la cantidad de código en comparación con los bucles for equivalentes.
  • Legibilidad: la comprensión del diccionario puede hacer que su código sea más explícito y legible.

En la práctica, puede utilizar la comprensión del diccionario cuando necesite realizar algunas de las siguientes operaciones:

  • Crear un diccionario a partir de un iterable existente
  • Fusione iterables en un diccionario mientras transforma claves, valores o ambos
  • Transformar claves de diccionario, valores o ambos
  • Filtrar un diccionario existente

Hasta ahora, ha aprendido a realizar todas estas operaciones utilizando la comprensión del diccionario. Aún así, puede encontrar otros buenos casos de uso para la comprensión de diccionarios durante su experiencia de codificación en Python.

Finalmente, hay situaciones en las que desea evitar la comprensión del diccionario. Por ejemplo, cuando desea procesar un conjunto de datos grande para producir pares clave-valor. El uso de la comprensión del diccionario en esta situación creará un diccionario grande y lo almacenará en la memoria, lo que resultará en un alto consumo de memoria.

Para hacer que su código sea eficiente en cuanto a memoria, puede usar una expresión generadora que produzca tuplas de la forma (clave, valor) en su lugar:

>>> squares_generator = ((x, x * x) for x in range(1_000_000))
>>> squares_generator
<generator object <genexpr> at 0x106e2ac20>

>>> next(squares_generator)
(0, 0)
>>> next(squares_generator)
(1, 1)
>>> next(squares_generator)
(2, 4)
>>> next(squares_generator)
(3, 9)

En este ejemplo, utilizará una expresión generadora para crear un iterador que produzca tuplas de dos valores. El primer valor es un número y el segundo es su valor al cuadrado.

El iterador resultante produce tuplas a pedido, lo que significa que solo usará memoria para almacenar una tupla a la vez. No necesita almacenar un diccionario de un millón de pares clave-valor en la memoria de su computadora y evitar esto hará que su código sea más eficiente.

En su lugar, puede utilizar la función incorporada next() para recorrer el iterador resultante, o puede utilizar un bucle for.

Explorando malas prácticas comunes

Debes evitar algunas malas prácticas al trabajar con comprensiones de diccionarios en tu código Python. Algunos de los más comunes incluyen los siguientes:

  • Usar expresiones complejas en comprensiones
  • Escribir comprensiones anidadas con varias cláusulas for o varios condicionales
  • Ejecutar transformaciones costosas mientras se construyen las claves y los valores
  • Intentar acceder a variables de comprensión desde el exterior

A veces, puedes terminar con un diccionario de comprensión donde la expresión de comprensión es demasiado complicada. Por ejemplo, es posible que desees aplicar transformaciones de forma condicional y pensar en algo como lo siguiente:

>>> fruits = {"apple": 1.0, "banana": 0.5, "cherry": 2.0, "mango": 2.3}
>>> with_discount = ["apple", "cherry"]

>>> {
...     fruit: price * 0.9 if fruit in with_discount else price
...     for fruit, price in fruits.items()
... }
{'apple': 0.9, 'banana': 0.5, 'cherry': 1.8, 'mango': 2.3}

En este sentido, se aplica un descuento de precio a una lista de frutas seleccionadas. Para hacer esto, use una expresión condicional como expresión de comprensión. Puede que le resulte difícil leer esta comprensión y descifrar lo que hace. Cuando una expresión complicada hace que su código sea difícil de leer, puede beneficiarse del uso de un bucle for normal para hacer que su código sea más legible.

Las comprensiones anidadas con varias cláusulas o condicionales for pueden hacer que el código sea menos legible. Entonces, en general, debes evitarlos y usar construcciones más legibles como un bucle normal.

No es posible intentar utilizar las variables que defines en una comprensión fuera de la comprensión misma:

>>> {value: value**3 for value in range(1, 11)}
{
    1: 1,
    2: 8,
    3: 27,
    4: 64,
    5: 125,
    6: 216,
    7: 343,
    8: 512,
    9: 729,
    10: 1000
}

>>> value
Traceback (most recent call last):
    ...
NameError: name 'value' is not defined

La variable value solo es visible dentro de la comprensión. Si intentas usarlo fuera de la comprensión, obtendrás un NameError.

A veces, cuando se trabaja con comprensiones de diccionarios, es posible que necesite ejecutar costosas transformaciones de datos para generar claves, valores o ambos. En esas situaciones, debe tener en cuenta que crear el diccionario final en la memoria puede llevar un tiempo considerable. Una posible solución es utilizar un generador que produzca pares clave-valor a pedido.

Conclusión

Ha aprendido en detalle sobre la comprensión del diccionario de Python. Son una herramienta poderosa para crear, transformar y filtrar diccionarios utilizando una sintaxis limpia y concisa. También ha aprendido sobre algunas malas prácticas y errores que debe evitar al trabajar con la comprensión del diccionario.

Las comprensiones de diccionarios son un recurso excelente para los desarrolladores de Python, ya que proporcionan una forma pitónica y simplificada de manipular diccionarios, que son estructuras de datos fundamentales en Python.

En este tutorial, usted:

  • Creado nuevos diccionarios con una sintaxis concisa
  • Diccionarios existentes transformados con comprensiones
  • Filtrado pares clave-valor no deseados de diccionarios
  • Decidió cuándo utilizar las comprensiones en su código

Con estas habilidades, puede escribir código Pythonic más legible para procesar diccionarios. A medida que continúe utilizando las comprensiones del diccionario, descubrirá que son una herramienta invaluable.