Словари¶
Автор(ы)
Что такое dict
¶
dict
(от английского «dictionary», словарь) – еще один тип данных в Python. Словари хранят пары ключ
: значение
. То есть в списках можно достать элемент, если указать его позицию в виде целого числа, а в словарях – тот самый ключ
. dict
– неупорядоченный тип данных, поэтому достать элемент по номеру не получится, но отображение содержимого будет в порядке добавления элементов. Уникальность ключей должна поддерживаться, чтобы всегда можно было быстро найти одно единственно верное значение
.
В некоторых языках программирования можно встретить ассоциативные массивы – полную аналогию dict
. Также вспомним базы данных, широко использующиеся во всём мире для хранения информации: в таблице можно установить первичный ключ, который уникально идентифицирует запись, как и ключ
соответствует значению
в словаре. Самый простой пример ключа - порядковый номер объекта!
Создание словаря¶
Использовать словарь стоит, когда нужно сохранять объекты с какими-то ключами и обращаться к объектам по известным ключам. Один из способов определения словаря: указание пар ключ
: значение
через^запятую внутри фигурных скобок {}
. Напоминает set
, правда? {}
позволяет создать пустой словарь, но не пустое множество.
Например, решили упростить себе жизнь и больше не запоминать дни рождения коллег. Вместо этого, лучше хранить их в одном месте:
В примере dates
имеет две пары значений. В первой паре строка "Кунг Фьюри"
является ключом, а "1968-09-09"
– его значением.
Получение значения по ключу¶
Чтобы получить значение по ключу, необходимо обратиться к переменной, содержащей словарь, и указать ключ в квадратных скобках []
:
Если указать неверный ключ в []
, Python будет ругаться: выбросит ошибку KeyError
и перестанет выполнять код. Чуть ниже посмотрим, как можно избежать таких ситуаций.
Изменение и добавление значений¶
Синтаксис изменения значения по ключу и добавления нового ключа со значением одинаковый: в []
нужно указать ключ, поставить =
и указать значение, которое теперь будет соответствовать ключу.
Если ключ уже был в словаре, значение по нему изменится на новое, а старое будет удалено. Указание нового ключа со значением добавляет пару в словарь.
Основные методы словаря¶
Проверка вхождения и get()
¶
Помните, ранее говорили, что обращение к несуществующему ключу приводит к ошибке? Пришло время посмотреть пару способов борьбы!
Можно проверить, есть ли интересующий ключ среди множества ключей словаря. Это делается при помощи бинарного оператора in
. Слева должен быть указан ключ, справа – переменная со словарем:
В коде проверку можно использовать в условной конструкции if
, чтобы принимать решение в зависимости от наличия ключа:
Теперь о методе get()
: при помощи его тоже можно получать значения из словаря по ключу. KeyError
никогда не появится: если ключа нет, по умолчанию возвращается None
:
Вторым аргументом метода get()
можно указать значение, которое должно возвращаться вместо None
, когда ключ не был найден:
Что такое "длина словаря"?¶
Функция len()
для словаря будет возвращать количество пар ключ
: значение
(их столько же, сколько ключей), которое в нём содержится:
Удаление из словаря¶
Есть несколько способов очистки в словаре: можно убирать по ключу, а можно сразу удалить все!
-
при помощи инструкции
del
(от английского «delete») можно удалить паруключ
:значение
(удаление ключа эквивалентно удалению парыключ
:значение
, так как теряем возможность найти то самоезначение
), в общем виде:Предположим, коллега из самого первого примера уволился и больше нет смысла хранить его день рождения:
-
pop()
- метод, который достает значение, хранящееся по переданному ключу, и сразу удаляет ключ из словаря:Для метода
pop()
есть возможность указать значение, которое будет возвращено при обращении к несуществующему ключу. Почти какget()
, но всё-таки, без указания этого значения,pop()
выбрасываетKeyError
. -
popitem()
имеет схожее название, но не путайте с предыдущим методом: этот на вход не принимаетключ
, а возвращает паруключ
:значение
, которая была добавлена последней (такое поведение гарантируется с Python 3.7). -
clear()
позволяет удалить сразу все ключи словаря, то есть полностью его очистить:
Важно
Обратите внимание на то, как работают методы pop()
, popitem()
и clear()
: как только вызываются, словарь меняет свой состав (изменения происходят in place, то изменить по месту без копирования).
Обновление и добавление ключей¶
Лицезрели, что значения в словарь можно добавлять или менять, обращаясь по ключу. Python предоставляет возможность не писать кучу присваиваний, а использовать лаконичный метод update()
, который на вход может принимать либо другой словарь, либо пары ключ
: значение
в какой-то последовательности (например, кортежи по два значения в списке: первое – ключ, второе – значение)
А что, если в update()
передать пары, ключ которых уже был в словаре? Значения по дублирующимся ключам будут перезаписаны на новые:
Доступ к ключам и значениям¶
В Python можно без проблем извлекать отдельно по ключам или значениям, а также итерироваться по элементам словарей в цикле for
. Осталось разобраться, как это работает.
Ключи¶
По умолчанию, в конструкциях вида
переменные цикла (тут – key
) будут принимать значения из множества ключей словаря. Аналогично можно использовать метод keys()
(позволяет достать все ключи), который явно говорит, что цикл идет по ключам, например:
player = 'Fred Weasley': quidditch_team[player] = '3rd year'
player = 'George Weasley': quidditch_team[player] = '3rd year'
player = 'Harry Potter': quidditch_team[player] = '2nd year'
Значения¶
При помощи метода values()
можно получить все значения, хранящиеся по всем ключам словаря:
Между тем
Напрямую по значению получить ключ нельзя.
Всё и сразу¶
Существует метод items()
, который достает пары ключ
: значение
в виде последовательности кортежей. Его же часто удобно использовать в циклах, дабы не тащить длинную запись в виде названия словаря и квадратных скобок с ключом при обращении к значению:
Player Fred Weasley is in 3rd year
Player George Weasley is in 3rd year
Player Harry Potter is in 2nd year
Сортировка¶
Функция sorted()
доступна и для словарей. По умолчанию ключи словаря поддерживают порядок, в котором были добавлены, но можно отсортировать их в нужном направлении (в зависимости от типа):
Не забудьте
Когда в функции передаётся просто название переменной со словарем, работа идет только над множеством ключей.
Можно ли отсортировать словарь по значениям?
Да, можно попробовать самостоятельно разобраться с аргументами функции sorted()
.
Что можно хранить¶
Теперь добавим немного технических подробностей: возможно, уже заметили самостоятельно, что dict
может принимать в качестве ключа не всякое значение. На самом деле только хешируемые объекты (можно вызвать функцию hash()
и получить значение) могут быть ключами словаря, на значения это ограничение не распространяется. В dict
и set
значение хеша от объекта используется для поиска внутри структуры.
Ключом словаря нельзя сделать объект изменяемого типа, например, list
, set
или сам dict
, так как значение их хеша может измениться со временем. Неизменяемый кортеж может быть ключом только если не содержит внутри изменяемые объекты.
Изменяемость и неизменяемость¶
В англоязычной литературе изменяемые типы называют mutable, а неизменяемые – immutable, почитать документацию.
В Python всё есть объект. Когда пользователь присваивает значение переменной, она начинает ассоциироваться с ячейкой памяти, где лежит это значение. Переменная знает адрес, откуда можно получить значение. id()
и hex()
показывают адрес в памяти компьютера. id()
- адрес в десятичном виде, а hex()
поможет перевести в шестнадцатеричный.
По адресу лежит так называемое внутреннее состояние переменной:
- неизменяемые типы не позволяют менять внутреннее состояние, значение переменной может поменяться только вместе с адресом
- изменяемые типы позволяют менять внутреннее состояние переменной при сохранении адреса (возвращаемое
id()
значение не меняется, но значение переменной каким-то образом преобразовывается). Изменение по ссылке называется изменением in place.
Неизменяемые типы¶
Из стандартных неизменяемыми являются:
int
float
bool
str
tuple
Давайте сразу рассмотрим пример:
flowchart LR
subgraph 100
0x10c678d50
end
counter --> 100
А теперь поменяем значение counter
:
Кажется, что раз значение переменной counter
поменялось, то и содержимое по предыдущему адресу изменилось? Нет, на самом деле counter
теперь указывает в другое место:
flowchart LR
subgraph 100
0x10c678d50
end
subgraph 200
0x10c6799d0
end
counter --> 200
Из интересного: Python заранее создает объекты для чисел от -5 до 256, поэтому для переменных со значением из этого диапазона берутся заранее готовые ссылки.
Изменяемые типы¶
Стандартные изменяемые типы это:
list
set
dict
У списков есть метод append()
, позволяющий добавить в него значение:
flowchart LR
subgraph list ["[1, 2, 3]"]
0x10df8d1c0
end
ratings --> list
После добавления ещё одного, адрес ratings
не изменился.
flowchart LR
subgraph list ["[1, 2, 3, 4]"]
0x10df8d1c0
end
ratings --> list
Что узнали из лекции¶
- новый тип данных – словарь! Позволяет хранить соответствие
ключ
:значение
; -
несколько способов создания
dict
, примеры: -
методы для изменения состояния или получения доступа к элементам:
-
требование к ключу: возможность хеширования, свойство ключа внутри словаря: уникальность;
- разобрали, что есть изменяемые (
dict
,set
,list
) и неизменяемые (int
,float
,bool
,tuple
,str
) стандартные типы данных.