Общий обзор словарей, демонстрирующий некоторые из наиболее популярных и используемых методов, которые можно применять к объектам словаря в Python.
Разобравшись с различными темами, связанными с наборами Python, мы теперь внимательно рассмотрим словари в Python и посмотрим, что они могут предложить.
Словарь в Python — это составной тип данных, который на самом деле просто причудливый способ сказать: «коллекция объектов». Теперь мы можем сказать то же самое о списках, кортежах или даже множествах, верно? Но что отличает словари?
Ну, во-первых, стоит отметить, что словари изменяемы. Мы можем изменить элементы по мере необходимости, объект сохранит свое id
на протяжении всего процесса изменения.
Во-вторых, они динамичны. Например, как и списки, словари могут увеличиваться и уменьшаться по мере необходимости.
Словари также могут быть вложенными. Нет ничего необычного в том, чтобы находить и работать со словарями словарей во время вашей повседневной работы.
Доступ к элементам словаря осуществляется с помощью клавиш. Элемент обычно представляет собой пару ключ-значение, где ключ представляет собой объект (например, строку), с помощью которого осуществляется доступ к значению, а затем оно извлекается или изменяется.
Не каждый объект может представлять собой ключ для словаря в Python. Главное требование к ключу — быть хешируемым. Вот почему изменяемые типы, такие как списки, наборы или даже словари, не могут работать как ключи. Если вы хотите больше по теме, это — хорошая отправная точка. Для нашей области достаточно помнить, что изменяемые типы не могут работать как ключи.
Создать словарь
Это можно сделать одним из двух способов:
- инициализированный словарь, в этом случае мы напишем что-то вроде
my_dict = { 1: "a", 2: "b", 3: "c" }
; - пустой словарь, хотя мы не можем использовать синтаксис фигурных скобок, например
my_dict = {}
, так как это заставит Python думать, что мы создаем набор. Чтобы правильно создать пустой словарь, мы должны использовать форму конструктора:my_dict = dict()
:
# initialized dictionary my_dictionary = {1: "a", 2: "b", 3: "c"} print(my_dictionary) # empty dictionary my_new_dict = dict() print(my_new_dict) Output: {1: 'a', 2: 'b', 3: 'c'} {}
Словари изменяемы
Вот как мы можем это проверить:
# initialize a dictionary and print it my_dictionary = {1: "a", 2: "b", 3: "c"} print(f"{id(my_dictionary)}: {my_dictionary}") # alter dictionary contents my_dictionary[4] = "d" my_dictionary[1] = "e" # same id, updated contents print(f"{id(my_dictionary)}: {my_dictionary}")
Итерация по словарю
В зависимости от того, что нам нужно, у нас есть разные сценарии:
# initialize a dictionary my_dictionary = {1: "a", 2: "b", 3: "c"} # iterate through the keys for key in my_dictionary: print(f"{key}") # same thing, different syntax: for key in my_dictionary.keys(): print(f"{key}") # iterate through the values for value in my_dictionary.values(): print(f"{value}") # iterate through the items for item in my_dictionary.items(): print(f"{item}") Output: 1 2 3 1 2 3 a b c (1, 'a') (2, 'b') (3, 'c')
Важно принять к сведению тот факт, что подход for item in dictionary
будет перебирать ключи по умолчанию. Если мы ищем значения, мы можем либо сделать более конкретное for item in dictionary.values()
, либо сделать это вместо этого:
for key in dictionary: print(f"{dictionary[key]}")
Затем, что немного интереснее, это вариант использования, в котором нам нужно задействовать метод dictionary.items()
. Это, как показано несколькими строками выше, возвращает объект, подобный множеству, состоящий из элементов словаря в виде кортежей, имеющих ключ в качестве первого элемента, за которым следует значение.
Копирование словаря
Как обычно, мы можем сделать это одним из двух способов: поверхностным копированием словаря или глубоким копированием словаря. Разница в том, что неглубокая копия словаря содержит ссылки на элементы скопированного словаря, в то время как глубокая копия также копирует элементы — рекурсивная неглубокая копия, если хотите.
Мелкая копия
Вот несколько способов поверхностного копирования словаря:
# initialize first dictionary my_dict = {1: {1: "a", 2: "b"}, 2: {3: "c", 4: "d"}} # shallow copy using dict constructor my_second_dict = dict(my_dict) # print them out print(f"{id(my_dict)}: {my_dict}") print(f"{id(my_second_dict)}: {my_second_dict}") # alter the second dict my_second_dict[2][5] = "e" # the change is reflected to the first dict print(f"{id(my_dict)}: {my_dict}") print(f"{id(my_second_dict)}: {my_second_dict}") Output: 139631010243008: {1: {1: 'a', 2: 'b'}, 2: {3: 'c', 4: 'd'}} 139631008981504: {1: {1: 'a', 2: 'b'}, 2: {3: 'c', 4: 'd'}} 139631010243008: {1: {1: 'a', 2: 'b'}, 2: {3: 'c', 4: 'd', 5: 'e'}} 139631008981504: {1: {1: 'a', 2: 'b'}, 2: {3: 'c', 4: 'd', 5: 'e'}}
Мы только что видели, как конструктор dict
на самом деле выполняет поверхностную копию словаря. Далее мы увидим, как можно использовать dict.copy()
для достижения того же эффекта:
# initialize first dictionary my_dict = {1: {1: "a", 2: "b"}, 2: {3: "c", 4: "d"}} # shallow copy using dict.copy() method my_second_dict = my_dict.copy() # print them out print(f"{id(my_dict)}: {my_dict}") print(f"{id(my_second_dict)}: {my_second_dict}") # alter the second dict my_second_dict[2][5] = "e" # the change is reflected to the first dict print(f"{id(my_dict)}: {my_dict}") print(f"{id(my_second_dict)}: {my_second_dict}") Output: 140086425994560: {1: {1: 'a', 2: 'b'}, 2: {3: 'c', 4: 'd'}} 140086426853824: {1: {1: 'a', 2: 'b'}, 2: {3: 'c', 4: 'd'}} 140086425994560: {1: {1: 'a', 2: 'b'}, 2: {3: 'c', 4: 'd', 5: 'e'}} 140086426853824: {1: {1: 'a', 2: 'b'}, 2: {3: 'c', 4: 'd', 5: 'e'}}
Глубокая копия
Рекурсивная неглубокая копия, глубокая копия может быть достигнута путем импорта copy
, а затем использования метода copy.deepcopy()
в целевом словаре:
import copy # initialize first dictionary my_dict = {1: {1: "a", 2: "b"}, 2: {3: "c", 4: "d"}} # deep copy my_second_dict = copy.deepcopy(my_dict) # print them out print(f"{id(my_dict)}: {my_dict}") print(f"{id(my_second_dict)}: {my_second_dict}") # alter the second dict my_second_dict[2][5] = "e" # the change is not reflected to the first dict print(f"{id(my_dict)}: {my_dict}") print(f"{id(my_second_dict)}: {my_second_dict}") Output: 140697250449024: {1: {1: 'a', 2: 'b'}, 2: {3: 'c', 4: 'd'}} 140697250459968: {1: {1: 'a', 2: 'b'}, 2: {3: 'c', 4: 'd'}} 140697250449024: {1: {1: 'a', 2: 'b'}, 2: {3: 'c', 4: 'd'}} 140697250459968: {1: {1: 'a', 2: 'b'}, 2: {3: 'c', 4: 'd', 5: 'e'}}
На этот раз изменение коснулось только второго словаря. Первый остается нетронутым. Как я уже говорил ранее, глубокое копирование — это не что иное, как рекурсивный процесс поверхностного копирования, должно быть совершенно очевидно, что глубокое копирование — обычно более медленный процесс, чем поверхностное копирование. В конце концов, все дело в том, что нам нужно: скорость против точности. Использование механизмов копирования во вложенных объектах (таких как вложенные списки или вложенные словари) без полного понимания основной разницы между поверхностным и глубоким копированием может привести к довольно коварным ошибкам в вашем программном обеспечении.
Очистка словаря
Предположим, у нас есть словарь, который содержит некоторые элементы, и по какой-то причине мы хотим, чтобы он был очищен:
# initialize a dictionary my_dict = {1: "a", 2: "b", 3: "c"} print(f"{id(my_dict)}: {my_dict}") # clear the dictionary my_dict.clear() print(f"{id(my_dict)}: {my_dict}") Output: 140374480416704: {1: 'a', 2: 'b', 3: 'c'} 140374480416704: {}
Инициализация словаря с заданными ключами и тем же значением
Бывают случаи, когда нам нужен словарь, инициализированный набором ключей и одинаковым значением для всех ключей, например, установка для всех ключей значения 0. Вот как мы можем элегантно добиться этого эффекта:
# declare list of keys my_keys = [1, 2, 3, 4] # all keys will have to have the value 10 my_value = 10 # create said dictionary and print it my_dict = dict.fromkeys(my_keys, my_value) print(f"{id(my_dict)}: {my_dict}") Output: 139942185766848: {1: 10, 2: 10, 3: 10, 4: 10}
Обратите внимание, что методу fromkeys()
не нужен фактический экземпляр словаря. Это статический метод, вызываемый в классе dict
. Следует отметить, что аргумент значения является необязательным. Если он не указан, он только инициализирует все указанные ключи значением None
.
Получить значение элемента из словаря
Есть два способа добиться этого: более прямой подход или более безопасный от ошибок подход. Прямой подход состоял бы в том, чтобы просто получить доступ к элементу: value = my_dictionary[key]
. Проблема с этим подходом заключается в том, что он вызовет исключение KeyError
, если key
не будет частью словаря.
Второй подход пытается найти ключ для получения соответствующего значения. Если запрошенного ключа нет, он возвращает значение по умолчанию, если оно предоставлено с таким аргументом. Если аргумент значения по умолчанию не указан, он просто возвращает None
:
# initialize a dictionary my_dict = {1: "a", 2: "b", 3: "c"} # this will return "a" element = my_dict.get(1, "d") print(element) # however, this will return "d" element = my_dict.get(5, "d") print(element) Output: a d
Получение элементов словаря, ключей и значений
Метод dictionary.items()
вернет все элементы словаря (пары ключ-значение, содержащиеся в словаре). Метод dictionary.keys()
вернет все ключи в словаре, а dictionary.values()
даст нам все значения в словаре:
# initialize a dictionary my_dict = {1: "a", 2: "b", 3: "c"} # print items print(f"{my_dict.items()}") # print keys print(f"{my_dict.keys()}") # print values print(f"{my_dict.values()}") Output: dict_items([(1, 'a'), (2, 'b'), (3, 'c')]) dict_keys([1, 2, 3]) dict_values(['a', 'b', 'c'])
Извлеките элемент из словаря
Удаление элемента из словаря по существу означает удаление указанной пары ключ-значение. Метод dictionary.pop()
сделает это за нас. Нам просто нужно предоставить ему аргумент — ключ, который мы хотим удалить:
# initialize a dictionary my_dict = {1: "a", 2: "b", 3: "c"} print(f"{id(my_dict)}: {my_dict}") # pop the first element and get its value value = my_dict.pop(1) print(f"{id(my_dict)}: {my_dict}") print(value) # try to pop a nonexistent element my_dict.pop(0) Output: 139790660993088: {1: 'a', 2: 'b', 3: 'c'} 139790660993088: {2: 'b', 3: 'c'} a Traceback (most recent call last): ... my_dict.pop(0) KeyError: 0
Как видно, вызов pop()
для элемента, которого нет в словаре, вызывает исключение KeyError
.
Есть еще один метод, который позволит нам удалять элементы. Метод dictionary.popitem()
удалит последний добавленный элемент. До Python 3.7 этот метод удалял случайный элемент из словаря. Вот краткая демонстрация метода в действии:
# initialize a dictionary my_dict = {1: "a", 2: "b", 3: "c"} print(f"{id(my_dict)}: {my_dict}") # pop and get the last item item = my_dict.popitem() print(item) print(f"{id(my_dict)}: {my_dict}") Output: 139680705994816: {1: 'a', 2: 'b', 3: 'c'} (3, 'c') 139680705994816: {1: 'a', 2: 'b'}
Вставьте пару ключ-значение по умолчанию в словарь
Метод dictionary.setdefault()
вставит новый элемент в словарь, используя предоставленные аргументы ключа и значения. Но только если его еще нет в словаре. В противном случае значение указанного ключа извлекается из словаря:
# initialize a dictionary my_dict = {1: "a", 2: "b", 3: "c"} # try to insert default value for key=1 value = my_dict.setdefault(1, "d") print(value) print(f"{id(my_dict)}: {my_dict}") # try to insert default value for key=4 value = my_dict.setdefault(4, "d") print(value) print(f"{id(my_dict)}: {my_dict}") Output: a 139972485861440: {1: 'a', 2: 'b', 3: 'c'} d 139972485861440: {1: 'a', 2: 'b', 3: 'c', 4: 'd'}
Когда ключ существует, он просто действует как подход dictionary.get(key)
или dictionary[key]
, эффективно извлекая значение для указанного ключа. Однако, когда ключ не существует, он не только возвращает указанное значение, но, в отличие от dictionary.get(key, default_value)
, это также изменяет словарь, эффективно создавая пару ключ-значение и вставляя ее в словарь.
Обновить элемент словаря
Метод dictionary.update()
принимает предоставленную пару ключ-значение, затем либо создает элемент, если он не существует, либо просто обновляет значение существующего ключа:
# initialize a dictionary my_dict = {1: "a", 2: "b", 3: "c"} print(f"{id(my_dict)}: {my_dict}") # update the key=1 element my_dict.update({1: "d"}) print(f"{id(my_dict)}: {my_dict}") # update the key=4 element my_dict.update({4: "d"}) print(f"{id(my_dict)}: {my_dict}") Output: 140049778729024: {1: 'a', 2: 'b', 3: 'c'} 140049778729024: {1: 'd', 2: 'b', 3: 'c'} 140049778729024: {1: 'd', 2: 'b', 3: 'c', 4: 'd'}
Объединить два словаря в один
Это довольно очевидно, хотя и не так очевидно. Мы можем использовать оператор pipe (|
) именно для этой цели:
# initialize two dictionaries my_dict_1 = {"key_1": "value_1"} my_dict_2 = {"key_2": "value_2"} # unify them into a third one and print it my_unified_dict = my_dict_1 | my_dict_2 print(my_unified_dict) Output: {'key1': 'value1', 'key2': 'value2'}
И с этим пришло время, чтобы мы завершили и это. Я попытался (и надеюсь, мне это тоже удалось) осветить наиболее часто используемые темы в словарях Python. Я с нетерпением жду возможности поделиться со всеми вами новыми знаниями и до следующего раза желаю вам только самого оглушительного успеха, чем бы вы ни занимались! Ваше здоровье!
Дека — инженер-программист, наставник, писатель, а иногда даже учитель. Обладая более чем 12-летним опытом разработки программного обеспечения, он теперь является настоящим сторонником языка программирования Python, а его страстью является помощь людям в оттачивании их навыков Python и программирования в целом. Вы можете связаться с колодой в Linkedin, Facebook, Twitter и Discord: Deck451#6188, а также следить за его публикациями здесь, на Medium.
Дополнительные материалы на PlainEnglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter и LinkedIn. Присоединяйтесь к нашему сообществу Discord.