Словари в Python: что нужно знать
4 апреля 2023 г.Словари считаются краеугольным камнем Python и любого языка программирования. Стандартная библиотека Python особенно полезна, предоставляя готовые к использованию сопоставления, которые могут быть очень эффективными при правильном использовании.
Итак, в этой статье мы обсудим, что делает словари Python особенными.
Понимание слова
Синтаксис понимания списка был адаптирован для словарей; dictComp создает экземпляр dict, беря пары {ключ: значение} из любого итерируемого объекта.
dial_codes = [
(55, 'Brazil'),
(86, 'China'),
(91, 'India'),
(62, 'Indonesia'),
(81, 'Japan'),
(7, 'Russia'),
(1, 'United States'),
]
country_dial = {country: code for code, country in dial_codes}
print(country_dial)
# {'Brazil': 55, 'China': 86, 'India': 91, 'Indonesia': 62, 'Japan': 81, 'Russia': 7, 'United States': 1}
code_less_than_70 = {code: country.upper() for country, code in sorted(country_dial.items()) if code < 70}
print(code_less_than_70)
# {55: 'BRAZIL', 62: 'INDONESIA', 7: 'RUSSIA', 1: 'UNITED STATES'}
Распаковка сопоставлений
Распаковка словарей аналогична распаковке списка, только вы будете распаковывать пару
{key: value} и это делается с помощью ** вместо оператора ***.**
Необходимо сохранить несколько ключевых моментов:
* Мы можем применить оператор ** к более чем одному аргументу в вызове функции.
* Повторяющиеся аргументы ключевого слова запрещены в вызовах функций, поэтому убедитесь, что распакованные словарные ключи уникальны.
* Оператор ** можно использовать внутри литерала dict также несколько раз.
def dump(**kwargs):
return kwargs
print(dump(**{'x': 1}, y=2, **{'z': 3}))
# {'x': 1, 'y': 2, 'z': 3}
print(dump(**{'x': 1}, y=2, **{'z': 3, 'x': 6}))
# TypeError: dump() got multiple values for keyword argument 'x'
print({'a': 0, **{'x': 1}, 'y': 2, **{'z': 3, 'x': 4}}
# Duplicate keys are allowed here and they get overwritten by the last occurence
#{'a': 0, 'x': 4, 'y': 2, 'z': 3}
Объединение словарей
Словари поддерживают операторы Set Union:
* Оператор | создает новое сопоставление при слиянии.
* Оператор |= обновляет первый операнд при слиянии.
d1 = {'a': 1, 'b': 3}
d2 = {'a': 2, 'b': 4, 'c': 6}
print(d1 | d2)
# overwriting the last occurence {'a': 2, 'b': 4, 'c': 6}
d1 |= d2
print(d1)
# {'a': 2, 'b': 4, 'c': 6}
Автоматическая обработка отсутствующих ключей
Представьте себе сценарий, в котором программа пытается получить доступ к значению в словаре по своему ключу, но не находит его. Есть два способа справиться с этим.
Используйте defaultdict
Экземпляр defaultdict создает элементы со значением по умолчанию по запросу всякий раз, когда отсутствующий ключ ищется с использованием синтаксиса d[k].
from collections import defaultdict
# Function to return a default values for keys that is not present
def def_value():
return "This guest did not check in yet"
# Defining the dict
d = defaultdict(def_value)
d["guest_1"] = "Adam"
d["guest_2"] = "Eve"
print(d["guest_1"]) # Adam
print(d["guest_2"]) # Eve
print(d["guest_3"]) # This guest did not check in yet
Реализовать метод ***Отсутствует***
Мы также можем реализовать метод missing в dict или любом другом типе сопоставления.
class GuestDict(dict):
def __missing__(self, key):
return 'This guest did not check in yet'
x = {"guest_1": "Adam", "guest_2": "Eve"}
guest_dict = GuestDict(x)
# Try accessing missing key:
print(guest_dict['guest_3'])
# This guest did not check in yet
Просмотр словаря
Методы экземпляра dict .keys(), .values() и .items() возвращают экземпляры классов с именами dict_keys, dict_values и dict_items, которые доступны только для чтения, но являются динамическими прокси настоящий дикт.
Если исходный dict обновлен, вы можете немедленно увидеть изменения в существующем представлении.
d = {'a': 5, 'b': 2, 'c': 0, 'd': 7}
v = d.values()
print('values before before updating : ', v)
# values before before updating : dict_values([5, 2, 0, 7])
d['e'] = 5
print('Dictionary after adding new value', d)
# Dictionary after adding new value {'a': 5, 'b': 2, 'c': 0, 'd': 7, 'e': 5}
# dynamic view object is updated automatically
print('value of the updated dictionary: ', v)
# value of the updated dictionary: dict_values([5, 2, 0, 7, 5])
Различные варианты Dict
Существуют различные варианты dict, готовые к использованию, и мы можем использовать их, чтобы выиграть время.
коллекции.OrderedDict
Это обычные словари, но они имеют некоторые дополнительные возможности, связанные с операциями упорядочения; вы можете найти больше о них здесь.
коллекции.ChainMap
Экземпляр ChainMap содержит список сопоставлений, которые можно поискать как единое целое.
Поиск выполняется для каждого входного сопоставления в том порядке, в котором оно появляется в вызове конструктора, и завершается успешно, как только ключ находится в одном из этих сопоставлений.
baseline = {'music': 'bach', 'art': 'rembrandt'}
adjustments = {'art': 'van gogh', 'opera': 'carmen'}
print(list(ChainMap(adjustments, baseline)))
# ['music', 'art', 'opera']
коллекции.Счетчик
Сопоставление, которое содержит целое число для каждого ключа. Обновление существующего ключа увеличивает его количество.
ct = collections.Counter('abracadabra')
print(ct)
# Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
ct.update('aaaaazzz')
print(ct)
# Counter({'a': 10, 'z': 3, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
print(ct.most_common(3))
# [('a', 10), ('z', 3), ('b', 2)]
полка.Полка
Модуль полки (название основано на том факте, что банки Pickle хранятся на полках) в стандартной библиотеке обеспечивает постоянное хранилище для сопоставления строковых ключей с объектами Python, сериализованными в двоичном формате Pickle.
UserDict
В UserDict есть несколько методов, готовых к использованию, вместо того, чтобы реализовывать или заново изобретать колесо, расширяя класс dict; подробнее об этом здесь.
MappingProxyType
Это класс-оболочка, который с учетом типа сопоставления возвращает экземпляр mappingproxy, который доступен только для чтения, но отражает изменения исходного сопоставления.
from types import MappingProxyType
d = {1: 'A'}
d_proxy = MappingProxyType(d)
print(d_proxy)
# mappingproxy({1: 'A'})
print(d_proxy[1])
# "A"
d[2] = 'B'
print(d_proxy)
# mappingproxy({1: 'A', 2: 'B'})
print(d_proxy[2])
# "B"
Механика словаря Python
Реализация dict в Python очень эффективна, так как основана на хэш-таблице, но следует помнить о нескольких вещах.
* Ключи должны быть хешируемыми объектами. Они должны реализовать правильные методы **hash** и eq.
* Доступ к элементу по ключу очень быстрый. В словаре могут быть миллионы ключей, но Python может найти ключ напрямую, вычислив хэш-код ключа и получив смещение индекса в хэш-таблице.
* Лучше не создавать атрибуты экземпляра dict вне метода init, так как это экономит память.
* Dicts неизбежно имеют значительные накладные расходы памяти.
Дополнительная литература
- Полная версия статьи находится в моем блоге.< /li>
- Третья глава книги Fluent Python.
- Документация по стандартной библиотеке Python, «типы данных контейнеров коллекций», включает примеры и практические рецепты с несколькими типами сопоставления.
- Документация по стандартной библиотеке Python на полках.
- Первая глава книги Python Cookbook, 3-е изд.
Оригинал