Словари
Списки и кортежи подходят для хранения последовательности элементов, но что, если нам удобнее обращаться к элементам по какому-то имени, а не по порядковому номеру? Для этого в Python предназначены словари. Вместо того чтобы хранить элементы по порядку, словари хранят пары «ключ-значение». Они похожи на настоящие словари, где у каждого слова (ключа) есть свое определение (значение).
Ключи словаря должны быть уникальными и представлены неизменяемым типом данных, например, числом, строкой, кортежем или даже замороженным множеством. На значения словаря никакие ограничения не накладываются.
Создание словаря
Существует несколько способов создания словарей в Python.
Однако при создании словаря всегда следует помнить о том, что ключи должны быть не только уникальными, но и представлены неизменяемым типом данных. Поэтому ключи не могут быть списками, множествами и другие словарями, но могут быть любыми числами, строками, кортежами и замороженными множествами.
Значениями же могут быть любые типы данных, в том числе, другие словари или вложенные коллекции.
Фигурные скобки для создания словаря
В самом простом случае словарь создаётся с помощью фигурных скобок, внутри которых через запятую перечисляются пары ключ: значение:
phone_book = {
"Мастер": "+79315555555",
"Маргарита": "+79637777777"
}
Функция dict() для создания словаря
Функция dict() создаёт словарь из пар «ключ-значение», которые могут быть переданы как именованные аргументы ключ=значение или последовательность кортежей с парами (ключ, значение).
|
Функция |
|
|
Описание |
Создаёт словарь из именованных аргументов или последовательности кортежей |
|
Параметры |
|
|
Возвращаемое значение |
Словарь |
Создание словаря с помощью именованных аргументов
Именованные аргументы позволяют передать функции значение по его имени. Например, мы уже передавали функции print() аргумент sep по его имени:
print("Одна овечка", "Две овечки", "Три овечки", sep=" * ")
# Вывод: Одна овечка * Две овечки * Три овечки
Функция dict(), в свою очередь, принимает аргументы с любыми именами. В таком случае имя аргумента будет ключом словаря, а сам аргумент – его значением:
phone_book = dict(Master="+79315555555", Margarita="+79637777777")
print(phone_book)
# Вывод:{'Master': '+79315555555', 'Margarita': '+79637777777'}
Однако так как имена переменных (аргументов) могут содержать только английские буквы, то и ключи в таком словаре будут написаны английскими буквами.
Создание словаря из последовательности кортежей
Также функции dict() можно передать последовательность (например, список или множество) кортежей, где каждый внутренний кортеж состоит из двух элементов: ключа и соответствующего ему значения:
phone_book_list = [
("Мастер", "+79315555555"),
("Маргарита", "+79637777777")
]
phone_book = dict(phone_book_list)
print(phone_book)
# Вывод: {'Мастер': '+79315555555', 'Маргарита': '+79637777777'}
Создание словаря из двух последовательностей
Если у нас есть две отдельные последовательности: одна содержит ключи, а другая – значения, то напрямую из них нельзя создать словарь, однако их можно попарно объединить с помощью функции zip(), и после этого уже передать функции dict().
Функция zip() создаёт итератор кортежей, где каждый кортеж содержит i-й элемент из каждого переданного объекта.
|
Функция |
|
|
Описание |
Возвращает итератор кортежей, в котором каждый кортеж содержит элементы переданных коллекций, стоящие на одинаковых позициях |
|
Параметры |
Необязательные параметры:
|
|
Возвращаемое значение |
Итератор кортежей |
Итератор – это объект, обеспечивающий последовательный доступ к элементам итерируемого объекта. Поэтому его нельзя вывести на экран, но можно передать функции dict() для создания словаря:
names = ["Мастер", "Маргарита"]
phones = ["+79315555555", "+79637777777"]
phone_book = dict(zip(names, phones))
print(phone_book)
# Вывод: {'Мастер': '+79315555555', 'Маргарита': '+79637777777'}
Последовательности ключей и значений должны иметь одинаковую длину, так как функция zip() останавливается, когда исчерпана самая короткая коллекция:
students = ["Курчатов И.В.", "Сахаров А.Д.", "Харитон Ю.Б."]
grades = [
{"Теплотехника": 4, "Химия": 5},
{"Теплотехника": 5, "Химия": 4}
]
students_dict = dict(zip(students, grades))
print(students_dict)
# Вывод: {'Курчатов И.В.': {'Теплотехника': 4, 'Химия': 5}, 'Сахаров А.Д.': {'Теплотехника': 5, 'Химия': 4}}
Но с помощью параметра strict=True можно изменить это поведение и в таком случае вызывать исключение ValueError.
Если функции zip() передать не два, а три списка, то каждый кортеж будет содержать три элемента, а если четыре списка – то четыре элемента и так далее. Однако словарь можно создать только на основе итератора, созданного из двух коллекций: ключей и значений.
Метод dict.fromkeys() для создания словаря
Метод dict.fromkeys() создаёт словарь с заданными ключами и единым значением для всех ключей.
|
Метод |
|
|
Описание |
Возвращает словарь, в котором ключи берутся из итерируемого объекта |
|
Параметры |
Необязательные параметры:
|
|
Возвращаемое значение |
Словарь |
Этот метод принимает последовательность ключей словаря и каждому ключу присваивает одинаковое значение (по умолчанию – None):
students = ["Ромашкина А.Г.", "Жасминова Д.Е.", "Пионов Г.У."]
students_grades_1 = dict.fromkeys(students)
print(students_grades_1)
# Вывод: {'Ромашкина А.Г.': None, 'Жасминова Д.Е.': None, 'Пионов Г.У.': None}
Значение по умолчанию изменяет параметр value:
students_grades_2 = dict.fromkeys(students, 0)
print(students_grades_2)
# Вывод: {'Ромашкина А.Г.': 0, 'Жасминова Д.Е.': 0, 'Пионов Г.У.': 0}
Если в качестве значения по умолчанию передать изменяемый объект (например, список), то все ключи получат ссылку на один и тот же объект:
students_grades_3 = dict.fromkeys(students, [])
students_grades_3["Ромашкина А.Г."].append(5)
print(students_grades_3)
# Вывод: {'Ромашкина А.Г.': [5], 'Жасминова Д.Е.': [5], 'Пионов Г.У.': [5]}
Изменение значения одного такого ключа приводит к изменению значений всех ключей, поэтому с изменяемыми объектами метод dict.fromkeys() следует использовать с осторожностью.
Создание пустого словаря
Пустой словарь создают функция dict() без аргументов и пустые фигурные скобки:
emperors_achievements = dict()
emperors_achievements = {}
Получение элементов словаря
Обращение к элементам словаря похоже на обращение к элементам списка или кортежа, но вместо индекса в квадратных скобках [] указывается ключ:
subjects = {
"Математика": "Mathematics",
"Физика": "Physics",
"Информатика": "Informatics"
}
print(subjects["Математика"])
# Вывод: Mathematics
Если элемент по указанному ключу отсутствует в словаре, то вызывается исключение KeyError:
print(subjects["Русский язык"])
# Ошибка: KeyError: 'Русский язык'
Метод dict.get() позволяет избежать этого, так как в таком случае возвращает значение по умолчанию.
|
Метод |
|
|
Описание |
Возвращает значение из словаря |
|
Параметры |
Необязательные параметры:
|
|
Возвращаемое значение |
Значение по ключу |
Теперь при обращении по несуществующему ключу будет возвращено значение по умолчанию – None:
subjects = {"Математика": "Mathematics",
"Физика": "Physics",
"Информатика": "Informatics"
}
print(subjects.get("Русский язык"))
# Вывод: None
Но его можно изменить с помощью параметра default:
print(subjects.get("Русский язык", "Отсутствует перевод слова"))
# Вывод: Отсутствует перевод слова
Метод dict.get() не изменяет словарь и значение default не добавляется в словарь по ключу key. Однако существует метод dict.setdefault(), который не просто возвращает значение по ключу, а добавляет пару «ключ-значение» в словарь, если переданный ключ не был найден.
|
Метод |
|
|
Описание |
Возвращает значение из словаря |
|
Параметры |
Необязательные параметры:
|
|
Возвращаемое значение |
Значение по ключу |
Если ключ есть в словаре, то он, как и метод dict.get(), возвращает его значение:
user = {"username": "grand_elf99", "email": "rurik99@example.ru"}
print(user.setdefault("username", "Не указан"))
# Вывод: grand_elf99
Но если ключ не найден, то метод dict.setdefault() сначала добавляет пару key: default в словарь, а затем уже возвращает значение по добавленному ключу:
age = user.setdefault("Возраст")
print(age)
# Вывод: None
print(user)
# Вывод: {'Логин': 'grand_elf99', 'Почта': 'rurik99@example.ru', 'Возраст': None}
По умолчанию значением не найденного ключа будет None, но параметр default позволяет это изменить:
age = user.setdefault("Возраст", 50)
print(age)
# Вывод: 50
print(user)
# Вывод: {'Логин': 'sauron4ever', 'Почта': 'biglord@example.ru', 'Возраст': 50}
Добавление и изменение элементов словаря
Для добавления нового элемента в словарь достаточно присвоить новое значение новому ключу:
goods = {"Телевизор": 12500, "Стиральная машина": 31999}
goods["Холодильник"] = 38499
print(goods)
# Вывод: {'Телевизор': 12500, 'Стиральная машина': 31999, 'Холодильник': 38499}
Ключи в словаре должны быть уникальными и каждый ключ соответствует только одному значению. Поэтому каждое новое значение перезаписывает предыдущее:
goods = {"Газовая плита": 27500, "Вентилятор": 999}
goods["Вентилятор "] = 1999
print(goods["Вентилятор "])
# Вывод: 1999
goods["Вентилятор "] = 2500
print(goods["Вентилятор "])
# Вывод: 2500
Объединение словарей
Метод dict.update(), и соответствующий ему оператор |=, дополняют словарь элементами другого словарь. Они эквиваленты друг другу и обновляют словарь, добавляя пары «ключ-значение» из другого словаря или итерируемого объекта. Если ключи уже существуют, их значения перезаписываются.
|
Метод |
|
|
Описание |
Дополняет исходный словарь |
|
Параметры |
|
|
Возвращаемое значение |
|
Таким образом можно добавить все элементы одного словаря в другой:
rooms = {"Комната 12А": "Алексей", "Комната 12Б": ["Кирилл", "Денис"]}
girls_rooms = {"Комната 13А": "Полина", "Комната 13Б": "Наталья"}
rooms.update(girls_rooms) # Эквивалентно rooms |= girls_rooms
print(rooms)
# Вывод: {"Комната 12А": "Алексей", "Комната 12Б": ["Кирилл", "Денис"], "Комната 13А": "Полина", "Комната 13Б": "Наталья"}
Или дополнить словарь последовательностью кортежей с парами (ключ, значение) и именованными аргументами ключ=значение:
profile = {"username": "lulu"}
extra_data = [
("email", "sunshine_00@example.ru"),
("extra_email", "kororeva_o@example.ru")
]
profile |= extra_data
profile.update(age=17)
print(profile)
# Вывод: {'username': 'lulu', 'email': ['sunshine_00@example.ru', 'ko-roreva_o@example.ru'], 'age': 17}
Однако метод dict.update() и оператор |= изменяют исходный словарь, что в некоторых случаях может быть нежелательным.
Объединить два словаря в один новый можно через распаковку словарей в новый словарь конструкцией {**dict1, **dict2} или с помощью оператора |. В обоих случаях создаётся новый словарь, а не изменяются исходные. При совпадении ключей используются значения из словаря dict2:
defaults = {"Цвет": "Красный", "Размер": "M"}
user_settings = {"Размер": "L", "Рукава": "Длинные"}
final_settings = defaults | user_settings
print(final_settings)
# Вывод: {'Цвет': 'Красный', 'Размер': 'L', 'Рукава': 'Длинные'}
Однако оператор | для объединения словарей появился только в Python 3.9, поэтому при использовании более старых версий языка словари объединяются через распаковку {**dict1, **dict2}:
final_settings1 = {**defaults, **user_settings}
print(final_settings)
# Вывод: {'Цвет': 'Красный', 'Размер': 'L', 'Рукава': 'Длинные'}
Удаление элементов словаря
Удалить элемент словаря можно только по ключу, но не по значению.
Удаление элемента по ключу с помощью оператора del
Оператор del в Python удаляет указанный объект, в том числе, элемент словаря:
flowers_meanings = {"Хризантема": "Дружба, "Кактус": "Схожесть характеров"}
del flowers_meanings["Хризантема"]
print(flowers_meanings)
# Вывод: {'Кактус': 'Схожесть характеров'}
Оператор del удаляет ссылку на объект, уменьшая счетчик ссылок на него. Если счетчик ссылок становится равным нулю, объект удаляется сборщиком мусора.
Однако при удалении несуществующего элемента будет вызвано соответствующее исключение, например, KeyError для словарей:
del flowers_meanings["Пионы"]
# Ошибка: KeyError: 'Тюльпаны красные'
Оператор del может удалять не только элементы словаря по ключу, но и элементы других коллекций, например, списка, а также целые переменные:
flowers = ["Роза", "Фиалка", "Ромашка"]
del flowers[1] # Удаление элемента списка по индексу
print(flowers)
# Вывод: ['Роза', 'Ромашка']
del flowers # Удаление переменной
print(flowers)
# Ошибка: NameError: name 'flowers' is not defined
Удаление и возвращение элемента
Если нужно не просто удалить, а ещё и вернуть удаляемый элемент, то для этого предназначен метод dict.pop().
|
Метод |
|
|
Описание |
Удаляет из словаря |
|
Параметры |
Необязательные параметры:
|
|
Возвращаемое значение |
Удаляемое значение |
Данный метод возвращает значение удаляемого элемента, но не ключ:
flowers_meanings = {
"Кактус": "Схожесть характеров",
"Примула": "Объяснение в любви"
}
del_flower_meanings = flowers_meanings.pop("Кактус")
print(del_flower_meanings)
# Вывод: Схожесть характеров
print(flowers_meanings)
# Вывод: {'Примула': 'Объяснение в любви'}
Также метод dict.pop() не вызывает исключение KeyError, а возвращает значение по умолчанию (None или другое указанное значение):
flowers_meanings = {
"Кактус": "Схожесть характеров",
"Примула": "Объяснение в любви"
}
del_flower_meanings = flowers_meanings.pop("Одуванчик", "Элемент не найден")
print(del_flower_meanings)
# Вывод: Элемент не найден

Метод pop() используется для удаления и возвращения элемента в списках, множествах и словарях. Этот метод в Python пришёл из концепции стека – структуры данных, в которой элементы добавляются и удаляются только с одной стороны, а операция pop удаляет и возвращает последний элемент. Это похоже на стопку тарелок, с которой мы можем взять только верхнюю тарелку, и соответствует принципу LIFO (от англ. Last in, first out – Последним пришел, первым вышел). Однако в Python логику этой операции расширили для каждого типа данных.
Метод dict.popitem() не позволяет указать ключ элемента для удаления, а всегда удаляет последний добавленный элемент. При этом он возвращает не только значение, но и ключ удаляемого элемента в виде кортежа (ключ, значение).
|
Метод |
|
|
Описание |
Возвращает и удаляет последнюю добавленную пару |
|
Возвращаемое значение |
Кортеж |
До версии Python 3.7, метод dict.popitem() удалял случайную пару, но в более новых версиях языка он удаляет и возвращает последнюю добавленную пару, что опять же соответствует принципу LIFO и концепции стека:
statues = {
"Будда Весеннего Храма": "Китай",
"Рабочий и колхозница": "Россия",
"Статуя Единства": "Индия"
}
deleted_statue = statues.popitem()
print(deleted_statue)
# Вывод: ('Статуя Единства', 'Индия')
print(statues)
# Вывод: {'Будда Весеннего Храма': 'Китай', 'Рабочий и колхозница': 'Рос-сия'}
Удаление всех элементов словаря
Также можно полностью очистить словарь, используя метод dict.clear().
|
Метод |
|
|
Описание |
Удаляет все элементы словаря |
|
Возвращаемое значение |
|
Тогда словарь станет пустым:
movies = {
"Парк Юрского периода": "Стивен Спилберг",
"Мартин Скорсезе": "Славные парни",
"Кристофер Нолан": "Интерстеллар"
}
movies.clear()
print(movies)
# Вывод: {}
Вложенные словари
Одноуровневая структура словаря может показаться недостаточной при обработке сложных структур данных, таких как информация о людях, компаниях или товарах. Поэтому на помощь приходят вложенные словари, позволяющие создавать иерархическую структуру данных.
Например, в библиотеке нам может понадобиться хранить информацию о книгах по жанрам и авторам:
books = {
"Научная фантастика": {
"Кир Булычев": {
"Сто лет тому вперед": {
"Описание": "Приключения Алисы Селезнёвой",
"Год издания": 1976,
},
"Любовь к трём цукербринам": {
"Описание": "История любви и технологий будущего",
"Год издания": 2010,
}
}
},
"Историческая литература": {
"Борис Акунин": {
"Коронация": {
"Описание": "Приключения Эраста Фандорина",
"Год издания": 2000,
}
}
}
}
Чтобы обратиться к элементу вложенного словаря, нужно последовательно указывать ключи, начиная от внешнего уровня внутрь. Это очень похоже на индексацию во вложенных списках.
Например, если требуется получить данные о романе Бориса Акунина «Коронация», то запись будет выглядеть следующим образом:
data = books["Историческая литература"]["Борис Акунин"]["Коронация"]
print(data)
# Вывод: {'Описание': 'Приключения Эраста Фандорина', 'Год издания': 2000}
Примеры
Пример 1. Подсчёт частоты символов
Программа подсчитывает сколько раз каждый символ появляется в строке, введённой пользователем:
text = input("Введите строку для подсчёта частоты символов: ")
counter = dict.fromkeys(text, 0) # Начальное значение счётчика - 0
for char in text:
counter[char] += 1
print(counter)
Вывод:
Введите строку для подсчёта частоты символов: Карабас-Барабас
{'К': 1, 'а': 6, 'р': 2, 'б': 2, 'с': 2, '-': 1, 'Б': 1}
Пример 2. Анализ успеваемости студентов
Программа подсчитывает оценки студентов за экзамен:
grades = [5, 4, 3, 5, 4, 4, 3, 5, 4, 4, 2, 3, 5, 4, 3, 4, 4]
grade_counts = {} # Словарь для подсчёта оценок
for grade in grades:
# Если в словаре есть ключ с оценкой grade, то берём его значение
# Если в словаре нет ключа с оценкой grade, то берём 0
# После этого счётчик увеличивается на 1
grade_counts[grade] = grade_counts.get(grade, 0) + 1
for grade, count in grade_counts.items():
print(f"Оценка {grade}: {count} студентов")
Вывод:
Оценка 5: 4 студентов
Оценка 4: 8 студентов
Оценка 3: 4 студентов
Оценка 2: 1 студентов
Пример 3. Управление сессиями пользователей
Программа отслеживает активную сессию пользователя – это период времени, в течение которого пользователь взаимодействует с определенным приложением или сервисом, начиная с момента входа и заканчивая выходом или периодом бездействия:
active_sessions = {
"user123": {"ip": "192.168.1.1", "last_activity": "10m ago"},
"admin": {"ip": "10.0.0.5", "last_activity": "1m ago"},
"guest": {"ip": "172.16.0.10", "last_activity": "30m ago"}
}
# Закрываем сессию гостя
del active_sessions["guest"]
# Закрываем сессию пользователя и получаем её данные
user123_session_data = active_sessions.pop("user123")
print(f"Закрыта сессия user123: {user123_session_data}")
# Если нужно закрыть последнюю сессию (например, для освобождения ресур-сов)
if active_sessions:
session_key, session_data = active_sessions.popitem()
print(f"Закрыта последняя сессия: {session_key}, {session_data}")
# Закрываем все сессии при завершении работы сервера
active_sessions.clear()
print(f"Активные сессии: {active_sessions}")
Вывод:
Закрыта сессия user123: {'ip': '192.168.1.1', 'last_activity': '10m ago'}
Закрыта последняя сессия: admin, {'ip': '10.0.0.5', 'last_activity': '1m ago'}
Активные сессии: {}
Итоги
- Ключи в словаре должны быть уникальными и представлены неизменяемым типом данных. Каждый ключ соответствует только одному значению.
- Функция
dict()создаёт словарь из пар «ключ-значение», которые могут быть переданы как именованные аргументыключ=значениеили последовательность кортежей с парами(ключ, значение). - Функция
zip()возвращает итератор кортежей, в котором каждый кортеж содержит элементы переданных коллекций, стоящие на одинаковых позициях. Это позволяет попарно объединить две коллекции: ключи и значения, и передать их функцииdict()для создания словаря. - Для получения значения словаря в квадратных скобках указывается соответствующий ключ.
- Объединить два словаря в один новый можно через распаковку словарей в новый словарь конструкцией
{**dict1, **dict2}или с помощью оператора|. - Оператор
delудаляет ссылку на объект, например, на элемент словаря, списка или переменную.
|
Метод |
Описание |
|---|---|
|
|
Возвращает словарь, в котором ключи берутся из итерируемого объекта |
|
|
Возвращает значение из словаря |
|
|
Возвращает значение из словаря |
|
|
Дополняет исходный словарь |
|
|
Удаляет из словаря |
|
|
Возвращает и удаляет последнюю добавленную пару |
|
|
Удаляет все элементы словаря |
Задания для самопроверки
1. Как функции dict() передаются пары «ключ-значение» для создания словаря?
Пары «ключ-значение» могут быть переданы как именованные аргументы ключ=значение или последовательность кортежей с парами (ключ, значение).
2. Дан словарь food = {"Яблоки красные": "78 руб/кг", "Картофель свежий": "83 руб/кг", "Помидоры красные": "120 руб/кг"}. Выведите на экран стоимость 1 кг красных яблок и 1 кг жёлтых груш. Если в словаре нет данных о стоимости какого-то продукта, то выведите строку "Нет данных".
food = {
"Яблоки красные": "78 руб/кг",
"Картофель свежий": "83 руб/кг",
"Помидоры красные": "120 руб/кг"
}
print(food.get("Яблоки красные", "Нет данных"))
# Вывод: 78 руб/кг
print(food.get("Груши жёлтые", "Нет данных"))
# Вывод: Нет данных
3. Дан словарь capitals = {"Вологодская область": "Вологда", "Республика Татарстан": "Казань", "Республика Саха": "Якутск", "Германия": "Берлин"}. Измените столицу Вологодской области с "Вологда" на "Череповец" и удалите элемент с ключом "Германия". Полученный словарь выведите на экран.
capitals = {
"Вологодская область": "Вологда",
"Республика Татарстан": "Казань",
"Республика Саха": "Якутск",
"Германия": "Берлин"
}
capitals["Вологодская область"] = "Череповец"
del capitals["Германия"]
print(capitals)
# Вывод: {'Вологодская область': 'Череповец', 'Республика Татарстан': 'Казань', 'Республика Саха': 'Якутск'}
4. Дан список кортежей team = [("Иван", 25), ("Мария", 30), ("Петр", 28)]. Преобразуйте этот список в словарь, где ключами являются имена, а значениями – возраст. Полученный словарь выведите на экран.
team = [("Иван", 25), ("Мария", 30), ("Петр", 28)]
team_dict = dict(team )
print(team_dict )
# Вывод: {'Иван': 25, 'Мария': 30, 'Петр': 28}
5. Дан список english_words = ["One", "Two", "Three", "Four", "Five"]. Создайте словарь, в котором ключи – числа от 1 до 5, а значения – перевод этих чисел на английский язык (список english_words). Полученный словарь выведите на экран.
numbers = list(range(1, 6))
english_words = ["One", "Two", "Three", "Four", "Five"]
numbers_dict = dict(zip(numbers, english_words))
print(numbers_dict)
# Вывод: {1: 'One', 2: 'Two', 3: 'Three', 4: 'Four', 5: 'Five'}
0 комментариев