Включения для словарей и множеств
В прошлом уроке конвейер складывал плитки в ящик-список. Теперь поменяем то, что стоит в конце ленты. Пусть пресс выбивает на каждой плитке ярлык и число под ним, а плитки попадают в картотеку, где число находят по ярлыку. Это словарь, и для него есть своё включение — в фигурных скобках.
Вы уже строили словарь циклом: создавали пустой словарь и в каждой итерации записывали значение по ключу. Сравните такой цикл с включением:
words = ["apple", "fig", "kiwi"]
lengths = {}
for w in words:
lengths[w] = len(w)
print(lengths) # {'apple': 5, 'fig': 3, 'kiwi': 4}
lengths = {w: len(w) for w in words}
print(lengths) # {'apple': 5, 'fig': 3, 'kiwi': 4}Давайте разберём обе версии:
- Цикл создаёт пустой словарь
lengthsи для каждого слова выполняетlengths[w] = len(w). - Включение
{w: len(w) for w in words}делает те же записи само. - Обе версии печатают
{'apple': 5, 'fig': 3, 'kiwi': 4}.
Во включении словаря перед for стоит пара «ключ: значение» через двоеточие. Каждая итерация добавляет в словарь одну пару, как присваивание lengths[w] = len(w) в цикле. Порядок работы тот же, что в списковом включении. Сначала работает for, затем фильтр if, если он есть, и последней — пара слева.
Три примера в фигурных скобках
Фигурные скобки умеют больше, чем перекладывать слова в словарь. В этом примере три включения:
words = ["ox", "to", "sun"]
print(sorted({len(w) for w in words})) # [2, 3]
prices = {"pear": 70, "plum": 40}
print({k: v * 2 for k, v in prices.items()}) # {'pear': 140, 'plum': 80}
print({k: v for k, v in prices.items() if v > 50}) # {'pear': 70}Множество
Если перед for стоит одно выражение без двоеточия, получается включение множества. На конвейере это ящик, который не принимает вторую плитку с тем же числом.
Длины слов здесь 2, 2 и 3. Множество хранит каждое значение один раз, поэтому две длины 2 дали один элемент. Порядка у множества нет, и для печати его оборачивают в sorted.
Новые значения из items()
Заголовок for k, v in prices.items() перебирает пары словаря. Распаковка раскладывает каждую пару по двум именам, как в обычном цикле.
Включение {k: v * 2 for k, v in prices.items()} оставляет ключи прежними, а цены удваивает. Получается новый словарь, а prices не меняется.
Фильтр по значению
Фильтр if после for работает так же, как в списковом включении. В словаре {k: v for k, v in prices.items() if v > 50} осталась только груша: она дороже 50, а слива дешевле.
Пары из zip
Ключи и значения часто лежат в двух списках одинаковой длины. Функция zip соединяет их в пары, а включение раскладывает каждую пару на ключ и значение.
Возьмём names = ["ann", "bob"] и scores = [90, 75]. Запись {n: s for n, s in zip(names, scores)} даёт {'ann': 90, 'bob': 75}. Если длины списков разные, zip остановится на коротком, и лишние ключи в словарь не попадут.
Повтор ключа
Здесь аналогия с картотекой перестаёт работать. В настоящей картотеке две карточки с одним ярлыком могут стоять рядом. В словаре ключ встречается один раз, и вторая пара с тем же ключом не добавляется, а заменяет значение.
Ошибки при этом нет. Как и запись d[k] = v в цикле, более поздняя пара заменяет значение, а ключ остаётся на прежнем месте:
names = ["anna", "bob", "alex"]
by_letter = {n[0]: n for n in names}
print(by_letter) # {'a': 'alex', 'b': 'bob'}
print(len(by_letter)) # 2Разберём по шагам:
- Первая итерация записывает
"anna"под ключом"a". - Вторая добавляет
"bob"под ключом"b". - Третья даёт тот же ключ
"a"и заменяет"anna"на"alex".
Поэтому в словаре две пары, а не три, и ключ "a" стоит первым, где его записала первая итерация. Этот вопрос часто задают на собеседовании: сколько пар окажется в словаре, если ключи повторяются.
Частая ошибка
Ключ и значение разделили запятой вместо двоеточия:
words = ["apple", "fig", "kiwi"]
lengths = {w, len(w) for w in words} # ✗SyntaxError: did you forget parentheses around the comprehension target?Перед for в фигурных скобках Python ждёт пару через двоеточие или одно выражение, а w, len(w) — два выражения. Поэтому файл не запускается. Скобки из подсказки дали бы множество кортежей {(w, len(w)) for w in words}, а не словарь. Словарь даёт двоеточие: {w: len(w) for w in words}.
Главное
- Включение словаря
{w: len(w) for w in words}ставит передforпару через двоеточие. - Без двоеточия фигурные скобки дают множество, и повторы в нём пропадают.
- При повторе ключа более поздняя пара заменяет значение, а ключ остаётся на первом месте.
- Запятая вместо двоеточия между ключом и значением —
SyntaxError.
Подпишись, чтобы пройти курс
Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.