Словари ломают мозг новичкам в программировании. Проблема в основном кроется в индексации: если в привычных списках каждый элемент имеет свой порядковый номер, то в словарях этим номером является произвольное (за некоторыми ограничениями) значение. Словари используются в любых крупных приложениях, и вам нужно обязательно знать основные методы, которые Python предоставляет для словаря: как его быстро создать, как создается копия словаря, как устанавливать в него значения и как из их словаря брать. Ниже мы рассмотрим два последних вопроса – как создавать новые пары {ключ: значение} и как безопасно брать их, используя встроенную функцию dict.
Перед тем как приступить непосредственно к главной теме статьи, имеет смысл немного подробнее описать актуальность умения работать со словарями для программистов, использующих Питон. Дело в том, что именно этот элемент нередко и совершенно справедливо называют базисом данного языка программирования. Даже утверждение, что Python попросту сформирован вокруг разнообразных словарей – модулей, классов, объектов и т.д. – если и является преувеличением, то очень небольшим.
В процессе программирования словари используются практически повсеместно и для решения самых разных задач. Для их индексирования используются ключи, каждый из которых имеет определенное значение. Именно такой подход к разработке ПО обеспечивает простоту и лаконичность программного кода, созданного с помощью Python. Стоит ли удивляться тому вниманию, которое уделяется изучению словарей в целом и конкретному поиску определенного ключа/значения в словаре. Причем задачу требуется решить таким образом, чтобы полученный результат не привел к неисправности или сбоям в работе программы.
Для этого и двух последующих способов мы будем использовать тестовый код, который вы сами можете запустить и посмотреть на результат. Первые 3 строки кода – инициализация – всегда будут одинаковыми. Вот они:
list_of_customers = ["Anna", "Ivan", "Peter"]
discount_amount = 5
customers_dictionary = {list_of_customers[i]: discount_amount for i in range(len(list_of_customers))}
Если вы не понимаете, что здесь происходит – смотрите раздел «Немного о списочных выражениях». В первой строке мы создаем список клиентов, во второй кладем в переменную базовую скидку для этих клиентов (5%), в третьей создаем словарь с парами {клиент: размер_скидки}. Если мы вызовем
print(customers_dictionary)
то увидим следующее:
{'Anna': 5, 'Ivan': 5, 'Peter': 5}
Если нам нужно узнать, какая скидка у клиента, мы можем написать
print(customers_dictionary["Anna"])
и в консоли появится число 5 – значение ключа “Anna”. Только вот если мы обратимся к любому несуществующему ключу (например, случайно напишем “Annna”), то Python 3 прервет исполнение и выбросит исключение. Программа будет принудительно закрыта процессором, и это точно не то, чего вам хотелось бы. Эту проблему можно обойти через обработку исключений, но для серьезного программирования Python такой выход не подходит – сложно, ненадежно. Python предоставляет куда более удобные методы взятия (и установки при необходимости) значения: методы .get() и .setdefault().
Главным недостатком такого способа вызова значения из словаря посредством квадратных скобок становится высокая вероятность выдачи программой исключения в виде ошибки, например, KeyError. Оно выступает следствием отсутствия ключа в словаре, что бывает достаточно часто. Особенно актуальной проблема является для объемных и часто меняющихся данных, характерных для значительной части динамических систем.
Чтобы нивелировать такой существенный минус, используются два метода. Первый предусматривает задействование конструкции try/except, которая предназначена для замены сообщения об ошибке на что-то более приятное, например, «Такой ключ отсутствует». В этом случае программный код имеет следующий вид.
try:
author['age']
except KeyError:
print('Такого ключа нет')
>>> 'Такого ключа нет'
Второй метод предполагает использованием встроенной библиотеки под названием collections или, что будет правильнее, готовой структуры из нее в виде defaultdict. Она представляет собой расширение к стандартным словарям, которое способно давать значение по умолчанию в случае запроса несуществующего ключа.
У словарей есть встроенные методы. Вам не нужно подключать дополнительные библиотеки, чтобы пользоваться ими – все уже подключено. Единственное, что вам нужно сделать – это создать словарь, после чего обратиться к его методу по стандартной форме:
some_dict.method_name(arguments)
Для того, чтобы использовать метод get() в примере выше, вам нужно написать:
print(customers_dictionary.get("Anna"))
Print можно и не писать, но тогда метод вернет значение в никуда, и оно просто исчезнет, а с помощью принта мы можем посмотреть результат. Приведенная выше строка кода выводит число «5».
А что будет, если мы с помощью этого метода обратимся к элементу, которого в словаре нет? Например, исполним следующий код:
print(customers_dictionary.get("Oleg"))
С этом случае .get() возвращает None. Причем он вернет None как отдельный объект – еще в ранних версиях Python для None и Void добавили отдельный тип объекта. По умолчанию None возвращается, когда искомый ключ не найден, но вы можете переопределить этот возврат, для чего у .get() есть второй, необязательный параметр. Если вы напишете:
print(customers_dictionary.get("Oleg", "Не найдено"))
то ответом будет строка «Не найдено», так как метод не смог найти указанный вами ключ. Если же вы укажете в качестве первого аргумента «Anna», а в качестве второго «Не найдено», то метод вернет число 5.
Метод .get() ничего не меняет в словаре – он только возвращает какое-то значение. Запомните, это будет важно дальше.
Есть еще один метод, возвращающий значение из словаря – .setdefault(). Он имеет 2 обязательных аргумента: какой ключ искать и что записывать в словарь, есть ключ не найден. Результата у исполнения этого метода может быть 2:
Другими словами, метод .setdefault() обладает следующим и весьма обширным функционалом, который включает:
Если мы исполним код:
print(customers_dictionary.setdefault("Anna", 10))
на экран будет выведено число «5», поскольку в словаре нашелся ключ «Anna» (и второй аргумент не был задействован). Если же мы исполним код:
print(customers_dictionary.setdefault("Oleg", 10))
то на экран будет выведено «10»: метод увидит, что ключа «Oleg» нет, после чего создаст его и в качестве значения укажет 10. Таким образом, .setdefault() обновляет словарь.
Зачем нужно иметь 2 разных метода? Потому что это удобно. Например, у вас есть словарь клиентов, и вам нужно проверить скидку одного конкретного клиента. Вы пишете запрос:
print(customers_dictionary.get("Annna", "Не найдено"))
Как видите, вы случайно допустили ошибку. Что будет, если вы используете .setdefault()? Создастся новый клиент Annna, и у этого клиента в скидке будет лежать строка «Не найдено». Это – очень плохо, потому что если у вас есть метод, перебирающий все ключи словаря и что-то делающий с числовыми значениями этих ключей, строка «Не найдено» вам все сломает.
А теперь предположим, что вы регистрируете нового клиента, которому нужно выдать скидку. Проблема в том, что клиент не помнит, регистрировался ли у вас раньше. Вы, конечно, можете методом .get() попытаться поискать его в базе, если клиент не будет найден – создать нового и назначить ему скидку. Но это – 3 строки кода. Зачем писать 3 строки кода, если можно уместить все в одну?
print(customers_dictionary.setdefault("Oleg", 5))
Если клиент будет найден, вам просто вернется величина его скидки – можете ни к чему ее не присваивать, и результат будет отброшен. А если клиента не было – он создастся со скидкой в 5%. И вам ничего не нужно проверять.
На всякий случай расскажем вам про пару фишек при работе со словарями, которые пригодятся вам в повседневной жизни. Одна из самых полезных – это списочные выражения, выше мы использовали один из них. У каждого iterable-объекта (того, элементы которого можно пересчитать) в Python есть списочное выражение (list comprehension). Если вас сбивает с точку слово «список» в названии, то поясняем – списочные выражения могут применяться не только к спискам, но списки эту фишку получили первыми, поэтому название и закрепилось. Создать словарь или другой перечисляемый объект в этом случае можно одной строкой кода, при этом можно тонко «настроить» его генерацию. Списочное выражение устроено следующим образом:
variable = {key: value for key in iterable if something}
где:
Последняя часть, «if something», не обязательна, остальные должны присутствовать. Работает все следующим образом:
Это может показаться сложным, но списочные выражения позволяют создавать большие и сложные словари в одну строку. Например, у вас есть словарь all_customers, в котором ключами указаны имена клиентов, а значениями – процент скидки. Вам нужно на основе этого словаря создать новый, customers_goe_10, в котором будут храниться все клиенты, у которых 10% скидки или больше (goe = greater or equal). Если вы не хотите перебирать ключи в цикле, можно сделать так:
customers_goe_10 = {item[0]: item[1] for item in all_customers.items() if item[1] >= 10}
Что за магия только что произошла? Все просто: у любого словаря есть ряд методов items (методы keys, values и непосредственно items). Когда вы обращаетесь к .items(), то получаете все значения в виде кортежа, то есть {“Anna”: 5} превращается в (“Anna”, 5). Каждая такая пара записывается в переменную item, значения можно получать по индексам: item[0] соответствует ключу (“Anna”), item[1] соответствует значению (5). Затем в новом словаре создается пара ключ: значение (item[0]: item[1]) при условии, что значение больше или равно 10 (if item[1] >= 10). Это повторяется для каждой пары из all_customers.
Школа |
Skillbox |
Стоимость |
104 551 руб |
Цена в рассрочку |
3 373 руб/мес |
Длительность курса |
10 месяцев |
Программа трудоустройства |
Есть |
Формат |
Запись лекций, Онлайн занятия с преподавателем |
Школа |
Skillfactory |
Стоимость |
164 873 руб |
Цена в рассрочку |
4 580 руб/мес |
Длительность курса |
18 месяцев |
Программа трудоустройства |
Есть |
Формат |
Запись лекций, Онлайн занятия с преподавателем |
Школа |
Академия «Синергия» |
Стоимость |
87 200 руб |
Цена в рассрочку |
3 633 руб/мес |
Длительность курса |
6 месяцев |
Программа трудоустройства |
Есть |
Формат |
Запись лекций, Онлайн занятия с преподавателем |
Вкратце: