Генераторы словарей
Некоторые замечательные возможности языка Python незаслуженно оставлены без внимания и многие программисты о них не знают. В этот раз речь пойдет о прекрасной возможности языка, делающей код яснее: генераторы словарей — однострочные выражения, возвращающие словарь. Но начнем с компактных генераторов списков и задачи удаления неуникальных элементов коллекций.
Будет интересно в основном новичкам в Python.
Генераторы списков
Самый простой способ создать список — использовать однострочное выражение — генератор списка. Он довольно часто применяется, и я встречал его во многих примерах и в коде многих библиотек.
Предположим, что у нас есть функция возвращающая какой-то список. Хороший пример — функция range(start, end), которая возвращает числа между start и end. Начиная с версии Python 3.0 она реализована как генератор и возвращает не сразу полный список, а выдает число за числом по мере необходимости. В Python 2.* для этого использовалась функция xrange(). Получение списка чисел от 1 до 10 при помощи этой функции могло бы выглядеть так:
numbers = [] for i in range(1, 11): numbers.append(i)
Если нам нужны только четные номера, мы могли бы реализовать это следующим образом:
numbers = [] for i in range(1, 11): if i % 2 == 0: numbers.append(i)
Генераторы списков делают код намного проще. Так выглядит выражение возвращающее список в общем виде:
[ expression for item in list if conditional ]
Используя его, первый пример можно переписать так:
numbers = [i for i in range(1, 11)]
а второе так:
numbers = [i for i in range(1, 11) if i % 2 == 0]
Конечно такой синтаксис на первый взгляд может показаться странным, но когда к нему привыкнешь — код станет проще и понятнее.
Удаление дубликатов
Другая часто встречающаяся задача при работе с коллекциями — удаление одинаковых элементов. Ее можно решить множеством методов.
Допустим мы работаем с таким списком:
numbers = [i for i in range(1,11)] + [i for i in range(1,6)]
Самый сложный способ удалить дубликаты, который мне встречался, выглядит так:
unique_numbers = [] for n in numbers: if n not in unique_numbers: unique_numbers.append(n)
Конечно и это работает, но есть решения попроще. Вы можете использовать стандартный тип множество(set). Множества не могу содержать одинаковые элементы по определению, таким образом если конвертировать список во множество — дубликаты удалятся. Но мы получим множество а не список, поэтому если мы хотим именно список уникальных значений — нужно сконвертировать еще раз:
unique_numbers = list(set(numbers))
Удаление одинаковых объектов
Совсем другая ситуация с объектами или словарями. Например у нас есть список словарей, в которых одно из значений используется в качестве идентификатора:
data = [ , , , , , ]
Удаление повторов может может быть реализовано большим или меньшим количеством кода. Конечно, чем меньше — тем лучше! Длинный вариант может выглядеть, например, так:
unique_data = [] for d in data: data_exists = False for ud in unique_data: if ud['id'] == d['id']: data_exists = True break if not data_exists: unique_data.append(d)
Можно получить то же результат, используя возможность, о которой я узнал пару дней назад: генераторы словарей. Они имеют похожий на генераторы списков синтаксис, но возвращают словарь:
Если переписать код из примера выше с использование этой фичи, останется всего одна сточка:
< d['id']:d for d in data >.values()
В этой строчке кода создается словарь, ключами которого являются поля, которые мы приняли за уникальный идентификатор, затем с помощью метода values() получаем все значения из созданного словаря. Т.к. словарь может содержать не больше одной записи для каждого ключа — полученный в итоге список не содержит дубликатов, что нам и требовалось.
Данная возможность была добавлена в Python 3.0 и бэкпортирована в Python 2.7, В более ранних версиях для решения подобной задачи можно использовать конструкцию такого вида:
dict((key, value) for item in list if condition)
Генерируется список кортежей (пар) и передается их конструктору dict(), который берет первый элемент кортежа как ключ, а второй как значение. При таком подходе решение всё той же задачи будет выглядеть так:
dict((d['id'], d) for d in data).values()
Генераторы словарей в Python
Словари (или dict) в Python — это, как и списки, способ хранения элементов. Но если в списке вы можете обращаться к элементам по их индексам, то в словаре доступ к элементам осуществляется с помощью ключей.
Вы создаете фиксированный ключ, назначаете ему значение и в дальнейшем получаете доступ к этому значению по ключу. В словаре вы имеете дело с парой «ключ-значение», которая иногда является более подходящей структурой данных для решения многих задач, чем простой список.
Работать со словарями питонисту приходится часто, особенно если он занимается наукой о данных. Поэтому сегодня мы поговорим о важном навыке, полезном при работе со словарями. Мы поговорим про генераторы словарей в Python.
- Что такое словарь в Python и как его можно эффективно использовать
- Генераторы словарей в Python: в чем их важность и как они могут служить альтернативой циклам for и лямбда-функциям
- Добавление условий в генератор. Мы будем работать с условиями if , несколькими условиями if , а также операторами if-else
- Что такое генератор вложенного словаря, как вы можете его использовать и как его можно потенциально переписать с помощью циклов for .
Итак, давайте приступать!
Словари в Python
Словарь в Python — это набор элементов, доступ к которым осуществляется по определенным ключам, а не по индексам. Что это значит?
Представьте словарь в реальном мире. Когда вам нужно найти значение слова, вы ищете в словаре само слово, а не его возможный индекс. Словари в Python работают по тому же принципу. Слово, значение которого вы ищете, является ключом, а значение этого слова является искомым значением. Вам не нужно знать индекс слова в словаре, чтобы найти его значение.
Примечание. Ключи в словаре должны быть хешируемыми.
Хеширование — это процесс прогона объекта через определенную функцию. Эта функция называется «хеш-функцией». Она возвращает уникальный результат для уникального входного значения.
Целые числа, числа с плавающей запятой, строки, кортежи и frozenset можно хэшировать. В то время как списки, словари и множества (кроме frozenset), не являются таковыми. Хеширование — довольно сложная тема, и это только основная концепция хеширования.
Инициализировать словарь в Python можно следующим образом:
a = a['doughnut'] = 'snack' print(a['apple']) # fruit
Но если вы обратитесь к элементу не по ключу ( print(a[‘apple’]) ), а по индексу ( print(a[0]) ), вы получите ошибку:
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) in () ----> 1 print(a[0]) KeyError: 0
Мы получили сообщение об ошибке типа KeyError, поскольку ключа 0 не существует.
Элементы словаря могут иметь любой тип данных. Посмотрите еще несколько примеров словарей, чтобы лучше это понять:
# Создание и вывод на экран словаря a = print(a) # # Добавление элемента в словарь (обновление словаря) a['one'] = 1.0 print(a) # # Удаление одного элемента del a['one'] print(a) # # Удаление всех элементов словаря a.clear() print(a) # <> # Удаление самого словаря del a print(a) --------------------------------------------------------------------------- NameError Traceback (most recent call last) in () 1 del a #Deletes the dictionary ----> 2 print(a) NameError: name 'a' is not defined
Важно помнить, что ключи в словаре должны быть уникальными, дубликаты не допускаются. Но в случае дублирования ключей Python не выдаст ошибку. Вместо этого он сочтет верным последний экземпляр ключа и просто проигнорирует первую пару ключ-значение. Посмотрите сами, как это работает:
sweet_dict = print(sweet_dict['a1']) # icecream
Генераторы словарей в Python
Генераторы словарей (dict comprehension) — это метод преобразования одного словаря в другой. Во время этого преобразования элементы исходного словаря, соответствующие заданным условиям, включаются в новый словарь. При этом каждый элемент может быть преобразован по мере необходимости.
Хороший генератор (списка, словаря, множества) может сделать ваш код более точным и, следовательно, более легким для чтения. При этом главное — не позволять им становиться слишком сложными. У вас не должно возникать проблем с пониманием того, что они делают. Придерживайтесь принципа «Хорошо то, что легко читается».
Работа с генераторами словарей в Python базируется на возможности доступа к ключам и значениям. А для доступа к ним в Python есть специальные строенные методы:
dict1 = # Поместить все ключи `dict1` в список и вернуть этот список dict1.keys() # dict_keys(['c', 'd', 'a', 'b']) # Поместить все значения, сохраненные в `dict1`, в список и вернуть этот список dict1.values() # dict_values([3, 4, 1, 2])
Итак, теперь вы знаете, как получить доступ ко всем ключам и их значениям в словаре. Вы также можете получить доступ ко всем парам ключей и значений в словаре, используя метод items() :
dict1.items() # dict_items([('c', 3), ('d', 4), ('a', 1), ('b', 2)])
Общий шаблон генераторов словарей в Python:
dict_variable =
Это самый простой вариант генератора. При добавлении условий код усложнится.
Давайте начнем с простого примера:
dict1 = # Удвоить каждое значение в словаре double_dict1 = print(double_dict1) #
В приведенном выше коде генератор создает новый словарь double_dict1 из словаря dict1 , просто удваивая каждое значение в нем.
Менять можно не только значения, но и ключи. Например, давайте создадим такой же словарь, что и выше, но изменим имена ключей. Выглядеть это будет так:
dict1_keys = print(dict1_keys) #
Зачем использовать генераторы словарей?
Генератор словарей — мощная концепция, которую можно использовать для замены циклов и лямбда-функций. При этом не все циклы for могут быть записаны как генератор словаря, но любой генератор можно переписать с использованием цикла for .
Рассмотрим следующую задачу. Вы хотите создать новый словарь, где ключами будут четные числа в диапазоне от 0 до 10, а значениями — квадраты этих чисел.
Давайте посмотрим, как можно решить эту проблему, используя цикл for и генератор словарей:
numbers = range(10) new_dict_for = <> # Добавляем значения в `new_dict` с помощью цикла for for n in numbers: if n%2==0: new_dict_for[n] = n**2 print(new_dict_for) # # Используем генератор словаря new_dict_comp =
Альтернатива циклам for
Циклы for используются для повторения определенной операции или блока инструкций в программе заданное количество раз. Однако вложенные циклы for (цикл for внутри другого цикла for ) могут стать запутанными и сложными. В таких ситуациях лучше подходят генераторы словарей. Они могут упростить чтение и понимание кода.
Альтернатива лямбда-функциям
Лямбда-функции — это небольшие анонимные функции. Т.е. функции без имени. Они являются одноразовыми функциями, которые нужны только там, где были созданы. Лямбда-функции в основном используются в сочетании с функциями filter() , map() и reduce() .
Давайте рассмотрим применение лямбда-функции вместе с функцией map() . Допустим, нам нужно преобразовать словарь с температурой по Фаренгейту в словарь с температурой по Цельсию.
# Инициализируем словарь `fahrenheit` fahrenheit = # Получаем соответствующие значения `celsius` celsius = list(map(lambda x: (float(5)/9)*(x-32), fahrenheit.values())) # Создаем словарь `celsius` celsius_dict = dict(zip(fahrenheit.keys(), celsius)) print(celsius_dict) #
Давайте разберем код. Во-первых, вам нужно определить математическую формулу, которая выполняет преобразование из градусов Фаренгейта в градусы Цельсия. В коде это делается с помощью лямбда-функции. Затем вы передаете эту функцию в качестве аргумента функции map() , которая применяет операцию к каждому элементу в списке fahrenheit.values() .
Помните функцию values() ? Она возвращает список, содержащий значения, хранящиеся в словаре.
Теперь у вас есть список, содержащий значение температуры в градусах Цельсия. Однако условие требует, чтобы это был словарь.
В Python есть встроенная функция zip() , которая перебирает элементы итераторов и объединяет их. Подробнее о функции zip() можно прочитать в статье «Используем zip() для парной итерации».
В приведенном выше примере функция zip() объединяет элементы из fahrenheit.keys() и списка градусов Цельсия, создавая пары ключ-значение, которые вы можете поместить в словарь с помощью функции dict , что и является желаемым результатом.
Теперь давайте попробуем решить ту же задачу, используя генератор словаря:
# Инициализируем словарь `fahrenheit` fahrenheit = # Получаем соответствующие значения в градусах Цельсия и создаем новый словарь `celsius` celsius =
Как видите, с использованием генератора словаря задача может быть решена с помощью одной строки кода. А в первой реализации потребовался двухэтапный процесс и понимание работы трех функций (лямбда, map() и zip() ).
Кроме того, благодаря генератору словаря решение становится интуитивно понятным и простым для чтения. Следовательно, генераторы словарей могут служить хорошей альтернативой лямбда-функциям.
Добавление условных выражений в генераторы словарей
При решении практических задач вам часто приходится добавлять в ваш код условия. Давайте рассмотрим, как можно добавить условные выражения в генератор словаря, чтобы сделать его более мощным.
Условие if
Предположим, вам нужно создать новый словарь из имеющегося, но с элементами, большими 2. Это означает, что вам нужно добавить условие к исходному шаблону, который вы видели выше. Сделать это можно следующим образом:
dict1 = # Проверка, больше ли элемент, чем 2 dict1_cond = 2> print(dict1_cond) #
Это не так сложно! Но что, если у вас несколько условий?
Несколько условий if
Допустим, что нам нужно не только получить элементы, большие двух, но и одновременно проверить, кратны ли они двум.
dict1_doubleCond = 2 if v%2 == 0> print(dict1_doubleCond) #
Мы просто добавляем условия в генератор одно за другим. Однако вам нужно быть осторожным с тем, что вы пытаетесь сделать в задаче. Помните, что последовательные операторы if работают так, как если бы между ними были логические and.
Давайте посмотрим еще один пример с тремя условными операторами:
dict1 = dict1_tripleCond = 2 if v%2 == 0 if v%3 == 0> print(dict1_tripleCond) #
При использовании цикла for решение будет выглядеть следующим образом:
dict1_tripleCond = <> for (k,v) in dict1.items(): if (v>=2 and v%2 == 0 and v%3 == 0): dict1_tripleCond[k] = v print(dict1_tripleCond) #
Условия if-else
Добавлять условия if-else в генератор словаря тоже просто. Убедитесь сами:
dict1 = # Определяем четные и нечетные элементы dict1_tripleCond =
Вложенные генераторы словарей
Вложенность — это организация данных слоями или нахождение объектов внутри других подобных объектов. Вы, должно быть, часто видели вложенную структуру if , которая представляет собой одно условие if внутри другого условия if .
Точно так же словари могут быть вложены друг в друга, и, следовательно, их генераторы тоже. Давайте посмотрим, что это означает:
nested_dict = , 'second':> float_dict = for (outer_k, outer_v) in nested_dict.items()> print(float_dict) # , 'second': >
Это пример вложенного словаря. nested_dict — это словарь с ключами first и second , значениями которых являются другие словари. Код работает со значениями внутреннего словаря и преобразует их в значения с плавающей запятой, а затем объединяет внешние ключи с новыми внутренними значениями с плавающей запятой в новый словарь.
Код также имеет вложенный генератор словаря, то есть один генератор внутри другого. Как видите, вложенный генератор словаря может быть довольно трудным как для чтения, так и для понимания. Использование генераторов при этом теряет смысл (ведь мы их применяем для улучшения читабельности кода).
По мере усложнения структуры словаря, с которым вы работаете, генераторы словарей в Python также начинают усложняться. В таких ситуациях может быть лучше не использовать сложные генераторы в коде.
Обратите внимание, что вы можете переписать приведенный выше фрагмент кода, используя вложенный цикл for , следующим образом:
nested_dict = , 'second':> for (outer_k, outer_v) in nested_dict.items(): for (inner_k, inner_v) in outer_v.items(): outer_v.update() nested_dict.update() print(nested_dict) # , 'second': >
Заключение
Итак, сегодня мы поговорили про генераторы словарей в Python. Мы повторили то, что знаем о словарях, и познакомились с концепцией генераторов. Кроме того, мы рассмотрели, где генераторы могут быть полезны, а где их лучше заменить циклом for . Теперь вы готовы эффективно работать с ними.
Надеемся, данная статья была вам полезна! Успехов в написании кода!
Генератор словарей в Python
Генераторы словарей являются мощным инструментом в Python, позволяющим создавать словари с помощью компактного и выразительного синтаксиса. Они представляют собой удобный способ создания словарей на основе итерации или условных выражений. Генераторы словарей позволяют нам эффективно и гибко создавать словари с минимальным количеством кода.
Основной синтаксис генератора словарей выглядит следующим образом:
Здесь ключ и значение — это выражения, определяющие ключ и значение для каждой пары в словаре. элемент представляет элемент из итерируемой последовательности, а последовательность — это источник данных, например, список или строка. условие (необязательно) определяет фильтрацию элементов в генераторе словарей.
Генераторы словарей предлагают нам большую гибкость при определении ключей и значений. Мы можем использовать условные выражения, функции и другие конструкции языка Python для определения значений словаря на основе заданных условий или преобразований.
В следующих разделах мы рассмотрим различные примеры и применения генераторов словарей, чтобы лучше понять их возможности и использование в практике.
Создание словаря с помощью генератора словарей
Генераторы словарей предоставляют нам удобный способ создания словарей с помощью одной строковой конструкции. Мы можем использовать генераторы словарей для создания словарей на основе итерации, условных выражений и других операций.
Одним из распространенных способов создания словаря с помощью генератора словарей является итерация по другому словарю или итерируемому объекту. Давайте рассмотрим пример:
source_dict = new_dict = print(new_dict)
В этом примере мы создаем новый словарь new_dict на основе элементов исходного словаря source_dict . Мы используем итерацию по методу items() , который возвращает пары ключ-значение словаря. Затем мы используем синтаксис генератора словарей, где каждая пара ключ-значение присваивается в новый словарь new_dict .
Результат выполнения кода будет:
Таким образом, мы успешно создали новый словарь, который полностью соответствует исходному словарю.
Применение функции к элементам при генерации словаря
В генераторе словарей в Python мы можем применять функцию к элементам во время создания словаря. Это позволяет нам модифицировать значения или ключи перед их включением в словарь.
Для применения функции к элементам при генерации словаря мы используем синтаксис, где мы указываем функцию и ее аргументы после двоеточия в выражении генератора словаря. Функция будет применяться к каждому элементу в соответствии с указанными аргументами, и результат будет использован в словаре.
students = age_dict = print(age_dict)
В этом примере мы создаем словарь age_dict , где ключами являются имена студентов из словаря students , а значениями являются возраст студентов, увеличенный на 1. Мы применяем функцию age + 1 к каждому значению возраста при генерации словаря.
Результат выполнения кода будет:
Таким образом, мы успешно создали словарь age_dict , в котором каждое значение возраста увеличено на 1.
Применение функции к элементам при генерации словаря позволяет нам изменять или обрабатывать значения и ключи на лету. Это дает нам большую гибкость при создании словарей и позволяет нам выполнять различные преобразования данных в процессе генерации словаря.
Включение элементов в генераторе словарей на основе условных выражений
Генераторы словарей в Python позволяют нам включать элементы в словарь на основе условных выражений. Это дает нам гибкость выбирать только определенные элементы для включения в словарь, в зависимости от заданных условий.
Для условного включения элементов в генераторе словарей мы можем использовать выражение if-else . Это позволяет нам проверить определенное условие и включить элемент в словарь, если условие выполняется, или пропустить его, если условие не выполняется.
Давайте рассмотрим пример:
numbers = [1, 2, 3, 4, 5] even_dict = print(even_dict)
В этом примере мы создаем словарь even_dict , в котором ключами являются числа из списка numbers , а значениями — квадраты этих чисел, если они являются четными, и строка «Odd» в противном случае. Мы используем условное выражение if num % 2 == 0 else «Odd» , чтобы определить, какое значение будет присвоено элементу в словаре.
Результат выполнения кода будет:
Таким образом, мы успешно создали словарь even_dict , в котором числа, являющиеся четными, имеют квадратное значение, а нечетные числа обозначены строкой «Odd».
Условное включение элементов в генераторе словарей предоставляет нам мощный инструмент для создания словарей с различными значениями в зависимости от условий. Это позволяет нам более гибко управлять содержимым словаря и адаптировать его под наши потребности.
Практические примеры использования генераторов словарей
Генераторы словарей предоставляют мощный инструмент для создания и преобразования словарей в Python. Они позволяют нам генерировать словари на основе различных источников данных, применять условия и функции к элементам, а также комбинировать их с другими структурами данных. Давайте рассмотрим несколько практических примеров, демонстрирующих использование генераторов словарей.
Пример: Генерация словаря с использованием списка студентов
Предположим, у нас есть список студентов и их оценки, и мы хотим создать словарь, где имена студентов будут ключами, а оценки — значениями.
students = ['Alice', 'Bob', 'Charlie'] scores = [85, 92, 78] student_scores = print(student_scores)
В этом примере мы использовали генератор словаря, чтобы создать словарь student_scores . Мы прошлись по списку students и списку scores одновременно, используя функцию zip() , и создали пары ключ-значение для каждого студента и его оценки.
Пример: Фильтрация словаря с использованием условия
Предположим, у нас есть словарь с информацией о студентах и их оценках, и мы хотим отфильтровать только тех студентов, у которых оценка выше определенного порога.
student_scores = threshold = 90 top_students = = threshold> print(top_students)
В этом примере мы использовали генератор словаря с условием if score >= threshold , чтобы отобрать только тех студентов, чьи оценки превышают заданный порог.
Пример: Преобразование словаря с применением функции
Предположим, у нас есть словарь с информацией о товарах и их ценах, и мы хотим создать новый словарь, где ключами будут названия товаров, а значениями — цены, округленные до двух знаков после запятой.
products = rounded_prices = print(rounded_prices)
В данном примере мы использовали генератор словаря, применив функцию round() к каждой цене товара. Функция round() округляет значение до указанного количества знаков после запятой.
Генераторы словарей предоставляют множество возможностей для создания и преобразования словарей в Python. Они являются компактным и эффективным способом работы с данными в словарях, позволяя выполнять различные операции с минимальным объемом кода. Используйте генераторы словарей, чтобы упростить и ускорить вашу работу со словарями в Python.
Генераторы множеств и словарей — Python: Декларативное программирование
Представим себе программиста на Python. Имея на руках список пар значений, он всегда может получить множество уникальных пар, применив к списку функцию set() .
Уже из этого множества легко получить словарь, применив функцию dict() . Кажется, что с помощью генераторов списков мы можем описывать словари и множества так же декларативно, как и списки.
Однако в большинстве случаев это неоптимальное решение: в памяти будет создан и сохранен целиком весь промежуточный список. Особенно неприятно будет тратить лишнюю память, если при генерации элементов множества или словаря возникнет много повторяющихся значений или ключей.
Python и здесь приходит нам на помощь. Он предоставляет генераторы множеств и генераторы словарей, которые мы изучим в этом уроке.
Генераторы множеств
С этими генераторами все максимально просто. Нужно всего два действия:
- Взять выражение, описывающее генератор списка
- Заменить в нем квадратные скобки на фигурные
Посмотрим, как это работает:
squares = x * x for x in range(10)> squares # 5 * 5 in squares # True
Вы получаете все те же возможности, которые доступны для генерации списков. Есть и дополнительное преимущество — при создании множества можно еще и проследить за тем, чтобы в список не попали дубли. Так можно сэкономить память.
Генераторы словарей
Генераторы словарей выглядят очень похоже на генераторы множеств. Разница заключается в том, как описывается элемент словаря.
Нужно сгенерировать не только значение, но и ключ. При этом ключ надо указать через двоеточие — так же, как при написании литерала словаря.
Посмотрим на примере:
char_positions = char: pos for pos, char in enumerate("Hello, World!")> char_positions # char_positions['o'] # 8
Обратите внимание, что в этом примере ключ ‘l’ имеет значение 10 . Посмотрим, какие значения имели char и pos во время генерации. Для простоты будем смотреть только на позиции символа ‘l’ :
[(char, pos) for pos, char in enumerate("Hello, World!") if char == 'l'] # [('l', 2), ('l', 3), ('l', 10)]
Как можно заметить, ‘l’ встречается в исходной строке три раза — в последнем случае как раз в позиции 10 . При генерации словаря используется последнее значение для каждого из ключей, будто словарь был заполнен в подобном цикле:
char_positions = <> for pos, char in enumerate("Hello, World!"): char_positions[char] = pos char_positions #
Открыть доступ
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
- 130 курсов, 2000+ часов теории
- 1000 практических заданий в браузере
- 360 000 студентов
Наши выпускники работают в компаниях:
