Словарь Python может содержать как несколько пар «ключ—значение», так и миллионы таких пар. Поскольку в словаре может храниться большой объем данных, Python предоставляет средства для перебора элементов словаря. Информация может храниться в словарях по-разному, поэтому предусмотрены разные способы перебора. Программа может перебрать все пары «ключ—значение» в словаре, только ключи или только значения.
Перебор всех пар «ключ—значение»
Прежде чем ознакомиться с разными способами перебора, рассмотрим новый словарь, предназначенный для хранения информации о пользователе веб-сайта. В следующем словаре хранится имя пользователя, его имя и фамилия:
user_0 = {
. .'username': 'efermi',
. .'first': 'enrico',
. .'last': 'fermi',
. .}
То, что вы уже узнали в этой главе, позволит вам обратиться к любому отдельному атрибуту user_0. Но что если вы хотите просмотреть все данные из словаря этого пользователя? Для этого можно воспользоваться перебором в цикле for:
user.py
user_0 = {
'username': 'efermi',
'first': 'enrico',
'last': 'fermi',
}
(1) for key, value in user_0.items():
(2) . .print("\nKey: " + key)
(3) . .print("Value: " + value)
Как мы видим в точке (1) , чтобы написать цикл for для словаря, необходимо создать имена для двух переменных, в которых будет храниться ключ и значение из каждой пары «ключ—значение». Этим двум переменным можно присвоить любые имена — с короткими однобуквенными именами код будет работать точно так же:
for k, v in user_0.items()
Вторая половина команды for в точке (1) включает в себя имя словаря, за которым следует вызов метода items(), возвращающий список пар «ключ—значение». Цикл for сохраняет компоненты пары в двух указанных переменных. В предыдущем примере мы используем переменные для вывода каждого ключа v, за которым следует связанное значение w. "\n" в первой команде print гарантирует, что перед каждой парой «ключ—значение» в выводе будет вставлена пустая строка:
Key: last
Value: fermi
Key: first
Value: enrico
Key: username
Value: efermi
Снова обратите внимание на то, что пары «ключ—значение» не возвращаются в порядке их хранения даже при переборе в словаре. Python не интересует порядок хранения пар «ключ—значение»; отслеживаются только связи между отдельными ключами и их значениями.
Перебор всех пар «ключ—значение» особенно хорошо работает для таких словарей, как в примере favorite_languages.py на с. 106: то есть для словарей, хранящих один вид информации со многими разными ключами. Перебрав словарь favorite_languages, вы получите имя каждого человека и его любимый язык программирования. Так как ключ всегда содержит имя, а значение — язык программирования, в цикле вместо имен key и value используются переменные name и language. С таким выбором имен читателю кода будет проще следить за тем, что происходит в цикле:
favorite_languages.py
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
(1) for name, language in favorite_languages.items():
(2) . .print(name.title() + "'s favorite language is " +
. . . .language.title() + ".")
Код в точке (1) приказывает Python перебрать все пары «ключ—значение» в словаре. В процессе перебора пар ключ сохраняется в переменной name, а значение — в переменной language. С этими содержательными именами намного проще понять, что делает команда print в точке (2).
Всего в нескольких строках кода выводится вся информация из опроса:
Jen's favorite language is Python.
Sarah's favorite language is C.
Phil's favorite language is Python.
Edward's favorite language is Ruby.
Такой способ перебора точно так же работает и в том случае, если в словаре будут храниться результаты опроса тысяч и даже миллионов людей.
Перебор всех ключей в словаре
Метод keys() удобен в тех случаях, когда вы не собираетесь работать со всеми значениями в словаре. Переберем словарь favorite_languages и выведем имена всех людей, участвовавших в опросе:
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
(1) for name in favorite_languages.keys():
. .print(name.title())
Строка (1) приказывает Python извлечь из словаря favorite_languages все ключи и последовательно сохранять их в переменной name. В выходных данных представлены имена всех людей, участвовавших в опросе:
Jen
Sarah
Phil
Edward
На самом деле перебор ключей используется по умолчанию при переборе словаря, так что этот код будет работать точно так же, как если бы вы написали
for name in favorite_languages:
вместо…
for name in favorite_languages.keys():
Используйте явный вызов метода keys(), если вы считаете, что он упростит чтение вашего кода, — или опустите его при желании.
Чтобы обратиться в цикле к значению, связанному с интересующим вас ключом, используйте текущий ключ. Для примера выведем для пары друзей сообщение о выбранном ими языке. Мы переберем имена в словаре, как это делалось ранее, но, когда имя совпадает с именем одного из друзей, программа будет выводить специальное сообщение об их любимом языке:
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
(1) friends = ['phil', 'sarah']
for name in favorite_languages.keys():
. .print(name.title())
. .
(2) . .if name in friends:
. . . .print(" Hi " + name.title() +
. . . . . .", I see your favorite language is " +
(3) . . . . . .favorite_languages[name].title() + "!")
В точке (1) строится список друзей, для которых должно выводиться сообщение. В цикле выводится имя очередного участника опроса, а затем в точке (2) программа проверяет, входит ли текущее имя в список друзей. Если имя входит в список, выводится специальное приветствие с упоминанием выбранного языка. Чтобы получить язык в точке (3), мы используем имя словаря и текущее значение name как ключ. Имя выводится для всех участников, но только друзья получают еще и специальное сообщение:
Edward
Phil
Hi Phil, I see your favorite language is Python!
Sarah
Hi Sarah, I see your favorite language is C!
Jen
Метод keys() также может использоваться для проверки того, участвовал ли конкретный человек в опросе:
favorite_languages = {
. .'jen': 'python',
. .'sarah': 'c',
. .'edward': 'ruby',
. .'phil': 'python',
. .}
(1) if 'erin' not in favorite_languages.keys():
. .print("Erin, please take our poll!")
Метод keys() не ограничивается перебором: он возвращает список всех ключей, и строка (1) просто проверяет, входит ли ключ 'erin' в список. Так как ключ в списке отсутствует, программа выводит сообщение:
Erin, please take our poll!
Упорядоченный перебор ключей словаря
Словарь всегда поддерживает связь между ключом и связанным с ним значением, но порядок получения элементов из словаря непредсказуем. Впрочем, это не создает проблем, потому что обычно требуется лишь получить правильное значение, связанное с каждым ключом.
Один из способов получения элементов в определенном порядке основан на сортировке ключей, возвращаемых циклом for. Для получения упорядоченной копии ключей можно воспользоваться функцией sorted():
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
for name in sorted(favorite_languages.keys()):
. .print(name.title() + ", thank you for taking the poll.")
Эта команда for не отличается от других команд for, если не считать того, что метод dictionary.keys() заключен в вызов функции sorted(). Эта конструкция приказывает Python выдать список всех ключей в словаре и отсортировать его перед тем, как перебирать элементы. В выводе перечислены все пользователи, участвовавшие в опросе, а их имена упорядочены по алфавиту:
Edward, thank you for taking the poll.
Jen, thank you for taking the poll.
Phil, thank you for taking the poll.
Sarah, thank you for taking the poll.
Перебор всех значений в словаре
Если вас прежде всего интересуют значения, содержащиеся в словаре, используйте метод values() для получения списка значений без ключей. Допустим, вы хотите просто получить список всех языков, выбранных в опросе, и вас не интересуют имена людей, выбравших каждый язык:
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
print("The following languages have been mentioned:")
for language in favorite_languages.values():
. .print(language.title())
Команда for читает каждое значение из словаря и сохраняет его в переменной language. При выводе этих значений будет получен список всех выбранных языков:
The following languages have been mentioned:
Python
C
Python
Ruby
Значения извлекаются из словаря без проверки на возможные повторения. Для небольших словарей это может быть приемлемо, но в опросах с большим количеством респондентов список будет содержать слишком много дубликатов. Чтобы получить список выбранных языков без повторений, можно воспользоваться множеством (set). Множество в целом похоже на список, но все его элементы должны быть уникальными:
favorite_languages = {
'jen': 'python',
'sarah': 'c',
'edward': 'ruby',
'phil': 'python',
}
print("The following languages have been mentioned:")
(1) for language in set(favorite_languages.values()):
print(language.title())
Когда список, содержащий дубликаты, заключается в вызов set(), Python находит уникальные элементы списка и строит множество из этих элементов. В точке (1) set() используется для извлечения уникальных языков из favorite_languages.values(). В результате создается не содержащий дубликатов список языков программирования, упомянутых участниками опроса:
The following languages have been mentioned:
Python
C
Ruby
В ходе дальнейшего изучения Python вы часто будете обнаруживать встроенные возможности языка, которые помогают сделать с данными именно то, что вам требуется.
Упражнения
6-4. Глоссарий 2: теперь, когда вы знаете, как перебрать элементы словаря, упростите код из упражнения 6-3, заменив серию команд print циклом, перебирающим ключи и значения словаря. Когда вы будете уверены в том, что цикл работает, добавьте в глоссарий еще пять терминов Python. При повторном запуске программы новые слова и значения должны быть автоматически включены в вывод.
6-5. Реки: создайте словарь с тремя большими реками и странами, по которым протекает каждая река. Одна из возможных пар «ключ—значение» — ‘nile’: ‘egypt’.
• Используйте цикл для вывода сообщения с упоминанием реки и страны — например, «The Nile runs through Egypt.»
• Используйте цикл для вывода названия каждой реки, включенной в словарь.
• Используйте цикл для вывода названия каждой страны, включенной в словарь.
6-6. Опрос: Возьмите за основу код favorite_languages.py (с. 106).
• Создайте список людей, которые должны участвовать в опросе по поводу любимого языка программирования. Включите некоторые имена, которые уже присутствуют в списке, и некоторые имена, которых в списке еще нет.
• Переберите список людей, которые должны участвовать в опросе. Если они уже прошли опрос, выведите сообщение с благодарностью за участие. Если они еще не проходили опрос, выведите сообщение с предложением принять участие.