Понимание словаря в Python 3 для начинающих

Если вы изучаете мир Python, вы, скорее всего, слышали много шумихи о понимании списков, но знаете ли вы, что есть еще такая вещь, как понимание словаря? Для тех, кто читает это и не знаком с пониманием списков, см. Мой предыдущий блог для помощи с этим. Этот блог будет расширять эти знания, чтобы обсудить основы понимания словаря, его сравнение с пониманием списка и что мы можем с этим сделать.

Что такое понимание словаря?

Как и понимание списка, понимание словаря принимает группу значений, выполняет над ними какую-то задачу и возвращает результат, но основное отличие от понимания списка состоит в том, что результат имеет форму словаря, а не списка. Прежде чем углубляться в это, убедитесь, что вы понимаете, что такое словарь и как он работает.

Общий синтаксис понимания словаря выглядит так:

{resulting_keys: resulting_values for iteration in series}

Поскольку словарь хранится в виде серии пар ключ-значение, разделенных двоеточием, имеет смысл, что выходная часть понимания словаря, resulting_keys: resulting_values, выглядит точно так же, как пара ключ-значение в словаре. Интуитивно мы заключаем смыслы словаря в те же фигурные скобки, которые мы использовали бы для обозначения словаря.

Входными данными для понимания словаря не обязательно должен быть словарь, но самый простой способ объяснить, как это работает, - это начать с примера преобразования одного словаря в другой.

Скажем, у меня есть следующий словарь:

my_dict = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

И я хочу изменить это так, чтобы все значения умножались на 2. Мы можем сделать это с помощью простого понимания словаря, например:

new_dict = {key: value * 2 for key, value in my_dict.items()}

new_dict теперь будет выглядеть так:

{'a': 2, 'b': 4, 'c': 6, 'd': 8, 'e': 10}

Основное отличие этого синтаксиса от понимания списка состоит в том, что вместо итерации по одной группе значений понимание словаря повторяется по двум группам в тандеме, группе ключей и группе значений. Вот почему в этом случае есть две повторяющиеся переменные, key, value, которые преобразуются в последнюю пару key: value. Метод items() преобразует словарь в список кортежей, которые можно читать как (key1, value1), (key2, value2), (key3, value3) и т. Д.

В приведенном выше примере мы только изменили значения и передали ключи в новый словарь как есть, но мы могли бы изменить и ключи, и значения одновременно, если бы захотели. Например, если бы я хотел сделать все буквы в my_dict заглавными, а также умножить все числа на 2, мы могли бы сделать это следующим образом:

new_dict = {key.upper(): value * 2 for key, value in my_dict.items()}

Тогда new_dict будет выглядеть так:

{'A': 2, 'B': 4, 'C': 6, 'D': 8, 'E': 10}

В некотором смысле, мы можем думать об этом как о выполнении двух составлений списков одновременно, одного для ключей и одного для значений. Однако нам не обязательно иметь две повторяющиеся переменные в каждом случае. Например, взгляните на список слов ниже:

words = ['car', 'house', 'plant', 'fisherman', 'picnic', 'rodeo']

Что, если бы я хотел создать словарь из этого списка, где ключи были бы сами слова, а значения были бы количеством букв в каждом слове. Вот как бы я это сделал:

word_dict = {word: len(word) for word in words}

Теперь у нас есть word_dict, который выглядит так:

{'car': 3, 'house': 5, 'plant': 5, 'fisherman': 9, 'picnic': 6, 'rodeo': 5}

Поскольку ключи и значения этого словаря являются функциями одного и того же words списка, нам нужна только одна повторяющаяся переменная для создания этого словаря, и это относительно просто выполнить.

Условные выражения в понимании словаря

Мы также можем выполнять фильтрацию и / или условную логику внутри понимания словаря. Это работает в основном так же, как и в понимании списка. Вот пример фильтрации словаря:

my_dict = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
new_dict = {key: val for key, val in my_dict.items() if val > 2}

Это вернет только пары ключ-значение, в которых значение больше 2, поэтому new_dict будет:

{'c': 3, 'd': 4, 'e': 5}

Мы также можем фильтровать по ключам. Давайте на этот раз добавим еще один фильтр к приведенному выше примеру на основе ключей:

new_dict = {key: val for key, val in my_dict.items() if val > 2 if key != 'd'}

Сначала мы отфильтровали все пары "ключ-значение", которые были не больше двух, а затем мы также отфильтровали все пары "ключ-значение" с ключом 'd'. Результат new_dict теперь:

{'c': 3, 'e': 5}

Мы также можем использовать операторы if и else вместе в понимании словаря, но, как и в понимании списка, синтаксис переключается, когда задействовано else:

my_dict = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
new_dict = {key: val + 10 if val > 3 else val + 20 for key, val in my_dict.items()}

Выход:

{'a': 21, 'b': 22, 'c': 23, 'd': 14, 'e': 15}

Здесь важно отметить, что условия не могут применяться одновременно к ключам и значениям одновременно. Вы должны относиться к ним как к отдельным. Другими словами, этот код выдаст синтаксическую ошибку:

new_dict = {key: val + 10 if val > 3 else key: val + 20 for key, val in my_dict.items()}

Проблема здесь в key: val + 20, потому что оператор else не распознает key, только val. Вы можете применять условные выражения как к ключам, так и к значениям, но это должно выглядеть примерно так:

new_dict = {(key.upper() if val > 2 else key): (val + 10 if val > 3 else val + 20) for key, val in my_dict.items()}

Я заключил два набора условных выражений в круглые скобки, чтобы упростить визуализацию, хотя это не требуется для работы кода. Первый набор круглых скобок будет использовать последние три ключа в my_dict с заглавной буквы, а второй набор круглых скобок добавит 20 к первым трем значениям и прибавит 10 к последним двум значениям, поэтому new_dict теперь будет:

{'a': 21, 'b': 22, 'C': 23, 'D': 14, 'E': 15}

Вы также можете связать несколько операторов if и else вместе, однако это может стать немного подробным и в определенный момент станет трудным для чтения. Просто нужно иметь в виду.

Вложенные термины словаря

Как и составные части списков, понимания словаря также могут быть вложены друг в друга. Если у нас есть словарь словарей, мы можем модифицировать их вложенными словарями. Вот пример, в котором мы умножаем каждое число во вложенных словарях ниже на 10:

my_dict = {
    'A': {
        'a': 1,
        'b': 2,
        'c': 3},
    'B': {
        'd': 4,
        'e': 5,
        'f': 6}
}

new_dict = {outer_key: {inner_key: inner_val * 10 for inner_key, inner_val in outer_val.items()} for outer_key, outer_val in my_dict.items()}

Выход:

{'A': {'a': 10, 'b': 20, 'c': 30}, 'B': {'d': 40, 'e': 50, 'f': 60}}

Поначалу этот пример может показаться трудным для понимания. Я бы начал с размышлений о том, что сначала делает внутреннее понимание словаря. Помните, что результат этого в целом представляет новый набор значений для внешнего словаря. Таким образом, это можно рассматривать как таковое:

new_dict = {outer_key: {outer_val} for outer_key, outer_val in my_dict.items()}

outer_val на самом деле является собственным словарем, в котором мы выполняем понимание словаря для каждого внутреннего словаря. Вкратце, это вложенные словари.

Как и в случае с пониманием списка, это представляет собой только начало того, что можно сделать с пониманием словаря, но, надеюсь, отсюда вы сможете найти свой путь через остальное.

Удачного кодирования!