Урок курса

Перебор словаря и вложенные структуры

Python для новичков

В прошлом уроке мы научились создавать словарь, читать значения по ключу, изменять и удалять пары. Теперь задача другая: пройтись по всему словарю в цикле. Python даёт для этого три метода — keys(), values() и items(). Начнём с первых двух.

Перебор ключей и значений: keys() и values()

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

Метод keys() возвращает все ключи словаря. Цикл по ним выглядит так:

grades = {'Анна': 5, 'Боб': 4, 'Вера': 3}

for name in grades.keys():
    print(name)

Вывод:

Анна
Боб
Вера

Есть нюанс: если написать просто for name in grades: без вызова .keys(), результат будет тот же — Python по умолчанию итерируется по ключам. Но явный .keys() делает код более читаемым, особенно когда важно подчеркнуть намерение.

Метод values() работает симметрично, но отдаёт значения:

for grade in grades.values():
    print(grade)

Вывод:

5
4
3

Главное ограничение values(): внутри цикла нет доступа к ключу. Если потребуется знать, чья это оценка — этот метод не поможет. Используйте его только когда ключ действительно не нужен: например, чтобы посчитать сумму всех оценок или найти максимум.

print(sum(grades.values()))   # 12
print(max(grades.values()))   # 5

Оба метода возвращают специальные объекты-представления (dict_keys и dict_values), а не обычные списки. Для большинства задач это не важно — они прекрасно работают в for и с функциями вроде sum(). Но если понадобится индексация или срез, придётся обернуть в list(): list(grades.keys()).

Перебор пар ключ-значение через items()

Методы keys() и values() дают доступ лишь к одной стороне словаря за раз. Но чаще всего нужно и имя, и значение одновременно — например, чтобы вывести «Анна: 5». Именно для этого существует items().

Метод возвращает представление, где каждый элемент — это пара (ключ, значение). В цикле for эта пара автоматически распаковывается в две переменные:

grades = {'Анна': 5, 'Боб': 4, 'Вера': 3}

for name, grade in grades.items():
    print(f'{name}: {grade}')

Вывод:

Анна: 5
Боб: 4
Вера: 3

Запись for name, grade in grades.items() работает потому, что Python распаковывает каждую пару точно так же, как распаковывает кортеж: два элемента — две переменные. Имена переменных здесь произвольные, но принято называть их по смыслу ключа и значения.

В отличие от keys() или values(), внутри цикла доступны обе части пары сразу — это и есть главное преимущество items(). Вы можете использовать name и grade независимо, строить f-строки, сравнивать, передавать в функции.

Практический критерий выбора прост:

  • Нужны только ключи — keys() (или просто for k in d).
  • Нужны только значения — values().
  • Нужны и ключ, и значение — items().

Словарь со списком в качестве значения и вложенный цикл

До сих пор значениями словаря были простые объекты — строки, числа. Но значением может быть и список. Это позволяет группировать несколько связанных элементов под одним ключом.

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

courses = {
    'математика': ['алгебра', 'геометрия'],
    'физика': ['механика', 'оптика']
}

Чтобы обратиться к конкретной теме, используется двойная индексация — сначала ключ словаря, затем индекс внутри списка:

print(courses['физика'][0])  # механика

Первая пара скобок достаёт список по ключу 'физика', вторая — берёт нулевой элемент из этого списка.

Когда нужно пройтись по всем предметам и их темам сразу, одного цикла не хватит. Внешний цикл перебирает пары предмет → список тем, внутренний — темы внутри каждого списка:

for subject, topics in courses.items():
    for topic in topics:
        print(f'{subject} — {topic}')

Вывод:

математика — алгебра
математика — геометрия
физика — механика
физика — оптика

Здесь subject — это ключ (название предмета), topics — список тем, который был значением в словаре. На каждой итерации внешнего цикла переменная topics содержит очередной список, и внутренний for topic in topics проходит по его элементам.

Это двухуровневая итерация: количество шагов внутреннего цикла зависит от длины каждого конкретного списка-значения, а не фиксировано заранее. Если у одного предмета три темы, а у другого — пять, внутренний цикл выполнится соответствующее количество раз.

Такую структуру — словарь, где ключи это категории, а значения это списки элементов — используют часто: список покупок по категориям, сотрудники по отделам, тэги по статьям. Паттерн один и тот же: внешний for k, v in d.items(), внутренний for item in v.

Безопасная итерация: изменение словаря в цикле

Есть одна ловушка, в которую легко попасть, когда цикл по словарю становится чуть сложнее — например, нужно удалить какие-то ключи прямо в процессе обхода.

Представим: есть словарь оценок, и мы хотим удалить всех студентов с оценкой ниже 4:

grades = {'Анна': 5, 'Боб': 3, 'Вера': 4, 'Глеб': 2}

for name, grade in grades.items():
    if grade < 4:
        del grades[name]  # ОШИБКА

Пython немедленно бросит RuntimeError: dictionary changed size during iteration. Причина в том, что grades.items() — это живое представление словаря, а не его копия. Изменить размер словаря (добавить или удалить ключ) во время итерации по нему запрещено: итератор теряет ориентацию и Python явно сигнализирует об этом.

Изменение значения у уже существующего ключа — другое дело, это разрешено. Ошибка возникает только при добавлении или удалении ключей.

Решение простое: итерироваться не по самому словарю, а по его копии. Для этого d.items() оборачивают в list():

grades = {'Анна': 5, 'Боб': 3, 'Вера': 4, 'Глеб': 2}

for name, grade in list(grades.items()):
    if grade < 4:
        del grades[name]

print(grades)  # {'Анна': 5, 'Вера': 4}

list(grades.items()) создаёт обычный список пар на момент начала цикла. Этот список никак не связан с живым состоянием словаря — удаление ключей из grades на него не влияет, и цикл проходит спокойно до конца.

Аналогичная ситуация возникает при итерации по list(d.keys()) с последующим del d[k] внутри — логика та же: оборачиваем в list(), получаем снимок ключей.

Если нужно не удалять, а собрать отфильтрованный словарь, ещё удобнее словарный comprehension — но это уже следующий инструмент. Пока достаточно запомнить правило: изменяешь словарь внутри цикла — итерируйся по копии.

Задача 1

Что выведет следующий код?

d = {'x': 10, 'y': 20, 'z': 30}
for k, v in d.items():
    print(k, v)
Выберите один вариант
Без регистрации · результат не сохраняется

Задача 2

Посмотрите на код:

prices = {'хлеб': 50, 'молоко': 80, 'масло': 120}
total = 0
for v in prices.values():
    total += v
print(total)

Что выведет программа?

Выберите один вариант
Без регистрации · результат не сохраняется

Задача 3

Какой цикл корректно перебирает одновременно ключи и значения словаря student?

Выберите один вариант
Без регистрации · результат не сохраняется

Задача 4

Что выведет следующий код?

menu = {'суп': ['борщ', 'уха'], 'салат': ['оливье']}
for dish, options in menu.items():
    for option in options:
        print(option)
Выберите один вариант
Без регистрации · результат не сохраняется

Задача 5

Посмотрите на словарь:

library = {
    'фантастика': ['Дюна', 'Марсианин'],
    'детектив': ['Шерлок Холмс']
}

Какое выражение вернёт строку 'Марсианин'?

Выберите один вариант
Без регистрации · результат не сохраняется

Задача 6

Что произойдёт при выполнении этого кода?

scores = {'Аня': 5, 'Борис': 3}
for name in scores:
    if scores[name] < 4:
        del scores[name]
Выберите один вариант
Без регистрации · результат не сохраняется

Задача 7

Сводка по турниру

У вас есть словарь stats с результатами турнира.

Нужно перебрать его методом items() и вывести по одной строке для каждой пары ключ-значение в формате:

победы: 12
ничьи: 4
поражения: 3

Порядок строк должен совпадать с порядком ключей в словаре.

РешениеPython

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Задача 8

Меню по категориям

У вас есть словарь menu с категориями блюд.

Нужно вывести каждую категорию и все блюда из неё в одной строке в формате:

завтрак: каша, чай
обед: суп, котлета, компот
ужин: омлет

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

Выводите одну строку на каждую категорию. Лишний текст печатать не нужно.

РешениеPython

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Задача 9

Убери слишком слабые лампы из плана

В файле уже задан словарь lights с названиями комнат и яркостью ламп.

Нужно удалить из словаря все пары, у которых значение меньше 3, а затем сохранить итоговый словарь в переменную lights.

Обязательно проходите по копии словаря, чтобы не получить ошибку изменения размера во время итерации.

В конце программы словарь должен содержать только комнаты с яркостью 3 и выше.

РешениеPython

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Задачи к уроку

Все задачи курса →

Продолжить с сохранением прогресса

Перейдите к уроку в учебном кабинете.

Перейти к интерактивному уроку