Содержание страницы
collections – Типы данных-контейнеры¶collections – Container datatypes
Исходный код: Lib/collections/__init__.py
Этот модуль предоставляет специализированные типы данных-контейнеры в качестве альтернативы
встроенным контейнерам общего назначения Python: dict, list,
set и tuple.
фабричная функция для создания подклассов кортежей с именованными полями |
|
контейнер, подобный списку, с быстрыми добавлением и извлечением с обоих концов |
|
класс, подобный словарю, для создания единого представления нескольких отображений |
|
подкласс dict для подсчёта хешируемых объектов |
|
подкласс dict, который запоминает порядок добавления записей |
|
подкласс dict, который вызывает фабричную функцию для предоставления отсутствующих значений |
|
обёртка вокруг словарей для упрощения создания подклассов dict |
|
обёртка вокруг списков для упрощения создания подклассов list |
|
обёртка вокруг строк для упрощения создания подклассов str |
ChainMap объекты¶ChainMap objects
Добавлено в версии 3.3.
Класс ChainMap предназначен для быстрой связки нескольких отображений,
чтобы их можно было рассматривать как единое целое. Часто он работает намного быстрее, чем создание
нового словаря и выполнение нескольких вызовов update().
Класс можно использовать для имитации вложенных областей видимости; он полезен в шаблонизаторах.
- class collections.ChainMap(*maps)¶
ChainMapгруппирует несколько словарей или других отображений вместе, создавая единое обновляемое представление. Если не указаны maps, создаётся один пустой словарь, так что новая цепочка всегда содержит как минимум одно отображение.Базовые отображения хранятся в списке. Этот список является открытым; к нему можно обращаться или изменять его через атрибут maps. Других состояний нет.
При поиске последовательно просматриваются базовые отображения, пока не будет найден ключ. В отличие от этого, записи, обновления и удаления работают только с первым отображением.
ChainMapвключает базовые отображения по ссылке. То есть, если одно из базовых отображений будет обновлено, эти изменения отразятся вChainMap.Поддерживаются все обычные методы словаря. Кроме того, имеется атрибут maps, метод для создания новых подконтекстов и свойство для доступа ко всем отображениям, кроме первого:
- maps¶
Обновляемый пользователем список отображений. Список упорядочен от первого просматриваемого к последнему. Это единственное сохраняемое состояние, и его можно изменять, чтобы менять порядок поиска отображений. Список всегда должен содержать хотя бы одно отображение.
- new_child(m=None, **kwargs)¶
Возвращает новый
ChainMap, содержащий новое отображение, за которым следуют все отображения из текущего экземпляра. Если указанm, он становится новым отображением в начале списка отображений; если не указан, используется пустой словарь, так что вызовd.new_child()эквивалентен:ChainMap({}, *d.maps). Если указаны какие-либо именованные аргументы, они обновляют переданное отображение или новый пустой словарь. Этот метод используется для создания подконтекстов, которые можно обновлять, не изменяя значения в родительских отображениях.Изменено в версии 3.4: Был добавлен необязательный параметр
m.Изменено в версии 3.10: Добавлена поддержка именованных аргументов.
- parents¶
Свойство, возвращающее новый
ChainMap, содержащий все отображения из текущего экземпляра, кроме первого. Это полезно для пропуска первого отображения при поиске. Варианты использования аналогичны ключевому словуnonlocal, применяемому в вложенных областях видимости. Также они параллельны встроенной функцииsuper(). Ссылка наd.parentsэквивалентна:ChainMap(*d.maps[1:]).
Обратите внимание, порядок итерации
ChainMapопределяется сканированием отображений от последнего к первому:>>> baseline = {'music': 'bach', 'art': 'rembrandt'} >>> adjustments = {'art': 'van gogh', 'opera': 'carmen'} >>> list(ChainMap(adjustments, baseline)) ['music', 'art', 'opera']
Это даёт тот же порядок, что и серия вызовов
dict.update(), начиная с последнего отображения:>>> combined = baseline.copy() >>> combined.update(adjustments) >>> list(combined) ['music', 'art', 'opera']
Changed in version 3.9: Added support for
|and|=operators, specified in PEP 584.
См. также
Класс MultiContext в пакете Enthought CodeTools имеет опции для поддержки записи в любое отображение в цепочке.
Класс Context в Django для шаблонов представляет собой цепочку отображений только для чтения. Он также поддерживает добавление и удаление контекстов, аналогично методу
new_child()и свойствуparents.Рецепт Nested Contexts содержит опции для управления тем, применяются ли записи и другие изменения только к первому отображению или к любому отображению в цепочке.
ChainMap Примеры и рецепты¶ChainMap Examples and Recipes
В этом разделе показаны различные подходы к работе с цепочечными отображениями.
Пример симуляции внутренней цепочки поиска Python:
import builtins
pylookup = ChainMap(locals(), globals(), vars(builtins))
Пример, когда заданные пользователем аргументы командной строки имеют приоритет над переменными окружения, которые, в свою очередь, имеют приоритет над значениями по умолчанию:
import os, argparse
defaults = {'color': 'red', 'user': 'guest'}
parser = argparse.ArgumentParser()
parser.add_argument('-u', '--user')
parser.add_argument('-c', '--color')
namespace = parser.parse_args()
command_line_args = {k: v for k, v in vars(namespace).items() if v is not None}
combined = ChainMap(command_line_args, os.environ, defaults)
print(combined['color'])
print(combined['user'])
Примеры шаблонов использования класса ChainMap для симуляции вложенных
контекстов:
c = ChainMap() # Создать корневой контекст
d = c.new_child() # Создать вложенный дочерний контекст
e = c.new_child() # Дочерний контекст c, независимый от d
e.maps[0] # Словарь текущего контекста – как locals() в Python
e.maps[-1] # Корневой контекст – как globals() в Python
e.parents # Цепочка объемлющих контекстов – как nonlocals в Python
d['x'] = 1 # Установить значение в текущем контексте
d['x'] # Получить первый ключ в цепочке контекстов
del d['x'] # Удалить из текущего контекста
list(d) # Все вложенные значения
k in d # Проверить все вложенные значения
len(d) # Количество вложенных значений
d.items() # Все вложенные элементы
dict(d) # Развернуть в обычный словарь
Класс ChainMap выполняет обновления (запись и удаление) только в
первом отображении цепочки, в то время как поиск просматривает всю цепочку. Однако,
если требуется глубокая запись и удаление, легко создать подкласс, который
обновляет ключи, найденные глубже в цепочке:
class DeepChainMap(ChainMap):
'Variant of ChainMap that allows direct updates to inner scopes'
def __setitem__(self, key, value):
for mapping in self.maps:
if key in mapping:
mapping[key] = value
return
self.maps[0][key] = value
def __delitem__(self, key):
for mapping in self.maps:
if key in mapping:
del mapping[key]
return
raise KeyError(key)
>>> d = DeepChainMap({'zebra': 'black'}, {'elephant': 'blue'}, {'lion': 'yellow'})
>>> d['lion'] = 'orange' # обновить существующий ключ на два уровня ниже
>>> d['snake'] = 'red' # новые ключи добавляются в самый верхний словарь
>>> del d['elephant'] # удалить существующий ключ на один уровень ниже
>>> d # отобразить результат
DeepChainMap({'zebra': 'black', 'snake': 'red'}, {}, {'lion': 'orange'})
Counter объекты¶Counter objects
Предоставляется инструмент счётчика для удобного и быстрого подсчёта. Например:
>>> # Подсчитать вхождения слов в списке
>>> cnt = Counter()
>>> for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
... cnt[word] += 1
...
>>> cnt
Counter({'blue': 3, 'red': 2, 'green': 1})
>>> # Найти десять самых распространённых слов в «Гамлете»
>>> import re
>>> words = re.findall(r'\w+', open('hamlet.txt').read().lower())
>>> Counter(words).most_common(10)
[('the', 1143), ('and', 966), ('to', 762), ('of', 669), ('i', 631),
('you', 554), ('a', 546), ('my', 514), ('hamlet', 471), ('in', 451)]
- class collections.Counter(**kwargs)¶
- class collections.Counter(iterable, /, **kwargs)
- class collections.Counter(mapping, /, **kwargs)
Counter– это подклассdictдля подсчёта хешируемых объектов. Это коллекция, в которой элементы хранятся как ключи словаря, а их количества – как значения словаря. Количествами могут быть любые целые числа, включая ноль или отрицательные. КлассCounterаналогичен мешкам (bags) или мультимножествам в других языках.Элементы подсчитываются из итерируемого объекта или инициализируются из другого отображения (или счётчика):
>>> c = Counter() # новый пустой счётчик >>> c = Counter('gallahad') # новый счётчик из итерируемого объекта >>> c = Counter({'red': 4, 'blue': 2}) # новый счётчик из отображения >>> c = Counter(cats=4, dogs=8) # новый счётчик из именованных аргументов
Объекты Counter имеют интерфейс словаря, за исключением того, что они возвращают ноль для отсутствующих элементов вместо возбуждения
KeyError:>>> c = Counter(['eggs', 'ham']) >>> c['bacon'] # счёт отсутствующего элемента равен нулю 0
Установка количества в ноль не удаляет элемент из счётчика. Используйте
delдля полного удаления:>>> c['sausage'] = 0 # запись счётчика с нулевым значением >>> del c['sausage'] # del действительно удаляет запись
Добавлено в версии 3.1.
Изменено в версии 3.7: Будучи подклассом
dict,Counterунаследовал возможность запоминать порядок вставки. Математические операции над объектами Counter также сохраняют порядок. Результаты упорядочиваются согласно времени первого появления элемента в левом операнде, а затем по порядку появления в правом операнде.Объекты Counter поддерживают дополнительные методы помимо тех, что доступны для всех словарей:
- elements()¶
Возвращает итератор по элементам, повторяя каждый столько раз, сколько указано в его количестве. Элементы возвращаются в порядке первого появления. Если количество элемента меньше единицы,
elements()игнорирует его.>>> c = Counter(a=4, b=2, c=0, d=-2) >>> sorted(c.elements()) ['a', 'a', 'a', 'a', 'b', 'b']
- most_common(n=None)¶
Возвращает список из n наиболее часто встречающихся элементов и их количества от самого частого к наименее частому. Если n опущено или
None,most_common()возвращает все элементы счётчика. Элементы с одинаковым количеством упорядочиваются в порядке первого появления:>>> Counter('abracadabra').most_common(3) [('a', 5), ('b', 2), ('r', 2)]
- subtract(**kwargs)¶
- subtract(iterable, /, **kwargs)
- subtract(mapping, /, **kwargs)
Элементы вычитаются из итерируемого объекта или из другого отображения (или счётчика). Подобно
dict.update(), но вычитает количества вместо замены. Как входные, так и выходные значения могут быть нулевыми или отрицательными.>>> c = Counter(a=4, b=2, c=0, d=-2) >>> d = Counter(a=1, b=2, c=3, d=4) >>> c.subtract(d) >>> c Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})
Добавлено в версии 3.2.
- total()¶
Вычисляет сумму количеств.
>>> c = Counter(a=10, b=5, c=0) >>> c.total() 15
Добавлено в версии 3.10.
Обычные методы словарей доступны для объектов
Counter, за исключением двух, которые работают с счётчиками иначе.- fromkeys(iterable)¶
Этот метод класса не реализован для объектов
Counter.
- update(**kwargs)¶
- update(iterable, /, **kwargs)
- update(mapping, /, **kwargs)
Элементы подсчитываются из итерируемого объекта или добавляются из другого отображения (или счётчика). Как и
dict.update(), но увеличивает счётчики вместо их замены. Кроме того, итерируемый объект должен быть последовательностью элементов, а не последовательностью(key, value)пар.
Счётчики поддерживают операторы расширенного сравнения для отношений равенства, подмножества и надмножества: ==, !=, <, <=, >, >=. Все эти проверки считают отсутствующие элементы имеющими нулевые счётчики, так что Counter(a=1) == Counter(a=1, b=0) возвращает истину.
Изменено в версии 3.10: Добавлены операции расширенного сравнения.
Изменено в версии 3.10: При проверке на равенство отсутствующие элементы считаются имеющими нулевые счётчики. Ранее Counter(a=3) и Counter(a=3, b=0) считались различными.
Типичные приёмы работы с объектами Counter:
c.total() # сумма всех значений
c.clear() # сбросить все значения
list(c) # список уникальных элементов
set(c) # преобразовать в множество
dict(c) # преобразовать в обычный словарь
c.items() # доступ к парам (элемент, кол-во)
Counter(dict(list_of_pairs)) # создать из списка пар (элемент, кол-во)
c.most_common()[:-n-1:-1] # n наименее частых элементов
+c # удалить нулевые и отрицательные значения
Для объединения объектов Counter в мультимножества (счётчики, у которых счётчики больше нуля) предоставляется несколько математических операций. Сложение и вычитание объединяют счётчики, складывая или вычитая счётчики соответствующих элементов. Пересечение и объединение возвращают минимум и максимум соответствующих счётчиков. Равенство и включение сравнивают соответствующие счётчики. Каждая операция может принимать входные данные со знаковыми счётчиками, но из результата исключаются значения со счётчиками, равными нулю или меньше.
>>> c = Counter(a=3, b=1)
>>> d = Counter(a=1, b=2)
>>> c + d # сложение двух счётчиков: c[x] + d[x]
Counter({'a': 4, 'b': 3})
>>> c - d # вычитание (остаются только положительные значения)
Counter({'a': 2})
>>> c & d # пересечение: min(c[x], d[x])
Counter({'a': 1, 'b': 1})
>>> c | d # объединение: max(c[x], d[x])
Counter({'a': 3, 'b': 2})
>>> c == d # равенство: c[x] == d[x]
False
>>> c <= d # включение: c[x] <= d[x]
False
Унарное сложение и вычитание – это сокращения для добавления пустого счётчика или вычитания из пустого счётчика.
>>> c = Counter(a=2, b=-4)
>>> +c
Counter({'a': 2})
>>> -c
Counter({'b': 4})
Добавлено в версии 3.3: Добавлена поддержка унарного плюса, унарного минуса и операций над мультимножествами на месте.
Примечание
Счётчики в первую очередь предназначены для работы с положительными целыми числами для представления текущих счётчиков; однако была предпринята осторожность, чтобы излишне не исключать варианты использования, требующие других типов или отрицательных значений. Чтобы помочь с такими вариантами, в этом разделе описаны минимальные ограничения по диапазону и типам.
Сам класс
Counterявляется подклассом словаря без ограничений на ключи и значения. Значения должны быть числами, представляющими счётчики, но в поле значения можно хранить что угодно.Метод
most_common()требует только упорядочиваемости значений.Для операций на месте, таких как
c[key] += 1, тип значения должен поддерживать только сложение и вычитание. Так что дроби, числа с плавающей запятой и десятичные числа будут работать, и отрицательные значения поддерживаются. То же самое верно дляupdate()иsubtract(), которые допускают отрицательные и нулевые значения как для входных, так и для выходных данных.Методы мультимножеств предназначены только для случаев использования с положительными значениями. Входные данные могут быть отрицательными или нулевыми, но создаются только выходные данные с положительными значениями. Ограничений на тип нет, но тип значения должен поддерживать сложение, вычитание и сравнение.
Метод
elements()требует целочисленных счётчиков. Он игнорирует нулевые и отрицательные счётчики.
См. также
Класс Bag в Smalltalk.
Статья в Википедии о мультимножествах.
Мультимножества в C++: учебное пособие с примерами.
О математических операциях над мультимножествами и их применении см. Кнут, Дональд. Искусство программирования, том II, раздел 4.6.3, упражнение 19.
Для перечисления всех различных мультимножеств заданного размера над заданным набором элементов см.
itertools.combinations_with_replacement():map(Counter, combinations_with_replacement('ABC', 2)) # --> AA AB AC BB BC CC
deque объекты¶deque objects
- class collections.deque([iterable[, maxlen]])¶
Возвращает новый объект deque, инициализированный слева направо (с помощью
append()) данными из итерируемого объекта. Если итерируемый объект не указан, новый deque пуст.Deque – это обобщение стеков и очередей (название произносится как «дек» и является сокращением от «double-ended queue» – двусторонняя очередь). Deque поддерживают потокобезопасные и эффективные по памяти добавления и удаления с любого конца с примерно одинаковой производительностью O(1) в обоих направлениях.
Хотя объекты
listподдерживают похожие операции, они оптимизированы для быстрых операций фиксированной длины и несут затраты на перемещение памяти O(n) для операцийpop(0)иinsert(0, v), которые изменяют как размер, так и положение базового представления данных.Если maxlen не указан или равен
None, deques могут расти до произвольной длины. В противном случае deque ограничен заданной максимальной длиной. Как только deque ограниченной длины заполняется, при добавлении новых элементов соответствующее количество элементов отбрасывается с противоположного конца. Deque с ограниченной длиной предоставляют функциональность, аналогичную фильтруtailв Unix. Они также полезны для отслеживания транзакций и других пулов данных, где интерес представляет только самая последняя активность.Объекты deque являются обобщёнными по типу своего содержимого.
Объекты deque поддерживают следующие методы:
- append(item, /)¶
Добавляет элемент в правую часть deque.
- appendleft(item, /)¶
Добавляет элемент в левую часть deque.
- clear()¶
Удаляет все элементы из deque, после чего его длина равна 0.
- copy()¶
Создаёт поверхностную копию deque.
Добавлено в версии 3.5.
- count(value, /)¶
Подсчитывает количество элементов deque, равных значению.
Добавлено в версии 3.2.
- extend(iterable, /)¶
Расширяет правую часть deque, добавляя элементы из итерируемого объекта.
- extendleft(iterable, /)¶
Расширяет левую часть deque, добавляя элементы из итерируемого объекта. Обратите внимание: последовательное добавление слева приводит к обращению порядка элементов в итерируемом объекте.
- index(value[, start[, stop]])¶
Возвращает позицию значения в deque (начиная с индекса start и до индекса stop). Возвращает первое совпадение или вызывает исключение
ValueError, если не найдено.Добавлено в версии 3.5.
- insert(index, value, /)¶
Вставляет значение в deque на позицию индекс.
Если вставка приведёт к тому, что ограниченный deque превысит maxlen, вызывается исключение
IndexError.Добавлено в версии 3.5.
- pop()¶
Удаляет и возвращает элемент из правой части deque. Если элемент отсутствует, вызывает исключение
IndexError.
- popleft()¶
Удаляет и возвращает элемент из левой части deque. Если элемент отсутствует, вызывает исключение
IndexError.
- remove(value, /)¶
Удаляет первое вхождение значения. Если не найдено, вызывает исключение
ValueError.
- reverse()¶
Переворачивает элементы deque на месте и возвращает
None.Добавлено в версии 3.2.
- rotate(n=1, /)¶
Поворачивает deque на n шагов вправо. Если n отрицательное, поворачивает влево.
Когда deque не пуст, поворот на один шаг вправо эквивалентен
d.appendleft(d.pop()), а поворот на один шаг влево –d.append(d.popleft()).
Объекты deque также предоставляют один атрибут только для чтения:
- maxlen¶
Максимальный размер дека или
None, если неограничен.Добавлено в версии 3.1.
В дополнение к вышесказанному, деки поддерживают итерацию, pickling, len(d),
reversed(d), copy.copy(d), copy.deepcopy(d), проверку принадлежности с помощью
оператора in и обращение по индексу, например d[0] для доступа
к первому элементу. Доступ по индексу выполняется за O(1) на обоих концах, но замедляется до O(n) в
середине. Для быстрого произвольного доступа лучше использовать списки.
Начиная с версии 3.5, деки поддерживают __add__(), __mul__() и __imul__().
Пример:
>>> from collections import deque
>>> d = deque('ghi') # создать новый deque с тремя элементами
>>> for elem in d: # обход элементов deque
... print(elem.upper())
G
H
I
>>> d.append('j') # добавить новый элемент справа
>>> d.appendleft('f') # добавить новый элемент слева
>>> d # показать представление deque
deque(['f', 'g', 'h', 'i', 'j'])
>>> d.pop() # вернуть и удалить правый элемент
'j'
>>> d.popleft() # вернуть и удалить левый элемент
'f'
>>> list(d) # вывести содержимое deque
['g', 'h', 'i']
>>> d[0] # посмотреть левый элемент
'g'
>>> d[-1] # посмотреть правый элемент
'i'
>>> list(reversed(d)) # вывести содержимое deque в обратном порядке
['i', 'h', 'g']
>>> 'h' in d # поиск в deque
True
>>> d.extend('jkl') # добавить несколько элементов за раз
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> d.rotate(1) # поворот вправо
>>> d
deque(['l', 'g', 'h', 'i', 'j', 'k'])
>>> d.rotate(-1) # поворот влево
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> deque(reversed(d)) # создать новую deque в обратном порядке
deque(['l', 'k', 'j', 'i', 'h', 'g'])
>>> d.clear() # очистить deque
>>> d.pop() # невозможно извлечь элемент из пустой deque
Traceback (most recent call last):
File "<pyshell#6>", line 1, in -toplevel-
d.pop()
IndexError: pop from an empty deque
>>> d.extendleft('abc') # extendleft() меняет порядок ввода на обратный
>>> d
deque(['c', 'b', 'a'])
deque Рецепты¶deque Recipes
В этом разделе рассматриваются различные подходы к работе с деками.
Деки с ограниченной длиной предоставляют функциональность, аналогичную фильтру tail в Unix:
def tail(filename, n=10):
'Return the last n lines of a file'
with open(filename) as f:
return deque(f, n)
Другой подход к использованию деков заключается в поддержании последовательности недавно добавленных элементов путем добавления справа и извлечения слева:
def moving_average(iterable, n=3):
# moving_average([40, 30, 50, 46, 39, 44]) --> 40.0 42.0 45.0 43.0
# https://en.wikipedia.org/wiki/Moving_average
it = iter(iterable)
d = deque(itertools.islice(it, n-1))
d.appendleft(0)
s = sum(d)
for elem in it:
s += elem - d.popleft()
d.append(elem)
yield s / n
Планировщик round-robin можно реализовать с помощью входных итераторов, хранящихся в deque. Значения выдаются из активного итератора в позиции ноль. Если этот итератор исчерпан, его можно удалить с помощью popleft(); в противном случае его можно вернуть в конец с помощью метода rotate():
def roundrobin(*iterables):
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
iterators = deque(map(iter, iterables))
while iterators:
try:
while True:
yield next(iterators[0])
iterators.rotate(-1)
except StopIteration:
# Удалить исчерпанный итератор.
iterators.popleft()
Метод rotate() позволяет реализовать deque срезы и удаление. Например, чистая реализация del d[n] на Python использует метод rotate() для позиционирования элементов, которые нужно извлечь:
def delete_nth(d, n):
d.rotate(-n)
d.popleft()
d.rotate(n)
To implement deque slicing, use a similar approach applying
rotate() to bring a target element to the left side of the deque. Remove
old entries with popleft(), add new entries with extend(), and then
reverse the rotation.
With minor variations on that approach, it is easy to implement Forth style
stack manipulations such as dup, drop, swap, over, pick,
rot, and roll.
defaultdict объекты¶defaultdict objects
- class collections.defaultdict(default_factory=None, /, **kwargs)¶
- class collections.defaultdict(default_factory, mapping, /, **kwargs)
- class collections.defaultdict(default_factory, iterable, /, **kwargs)
Возвращает новый объект, подобный словарю.
defaultdictявляется подклассом встроенного классаdict. Он переопределяет один метод и добавляет одну изменяемую переменную экземпляра. Остальная функциональность такая же, как у классаdict, и не документируется здесь.Первый аргумент задает начальное значение для атрибута
default_factory; по умолчанию он равенNone. Все остальные аргументы обрабатываются так же, как если бы они были переданы конструкторуdict, включая именованные аргументы.defaultdictявляются обобщенными по двум типам, обозначающим (соответственно) типы ключей и значений словаря.defaultdictобъекты поддерживают следующий метод в дополнение к стандартным операциямdict:- __missing__(key, /)¶
Если атрибут
default_factoryравенNone, возникает исключениеKeyErrorс аргументом key.Если
default_factoryне равенNone, он вызывается без аргументов для предоставления значения по умолчанию для заданного key; это значение вставляется в словарь для key и возвращается.Если вызов
default_factoryвызывает исключение, это исключение распространяется без изменений.Этот метод вызывается методом
__getitem__()классаdict, когда запрошенный ключ не найден; все, что он возвращает или возбуждает, затем возвращается или возбуждается методом__getitem__().Обратите внимание, что
__missing__()не вызывается для любых операций, кроме__getitem__(). Это означает, чтоget(), как и обычные словари, будет возвращатьNoneпо умолчанию, а не использоватьdefault_factory.
defaultdictобъекты поддерживают следующую переменную экземпляра:- default_factory¶
Этот атрибут используется методом
__missing__(); он инициализируется из первого аргумента конструктора, если он присутствует, илиNone, если отсутствует.
Изменено в версии 3.9: Добавлены операторы слияния (
|) и обновления (|=), указанные в PEP 584.
defaultdict Примеры¶defaultdict Examples
Используя list в качестве default_factory, легко сгруппировать последовательность пар ключ-значение в словарь списков:
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
... d[k].append(v)
...
>>> sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
Когда ключ встречается впервые, его еще нет в отображении; поэтому запись автоматически создается с помощью функции default_factory, которая возвращает пустой list. Затем операция list.append() присоединяет значение к новому списку. Когда ключи встречаются снова, поиск выполняется обычным образом (возвращается список для этого ключа), и операция list.append() добавляет еще одно значение в список. Этот метод проще и быстрее, чем эквивалентный метод с использованием dict.setdefault():
>>> d = {}
>>> for k, v in s:
... d.setdefault(k, []).append(v)
...
>>> sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
Установка default_factory в int делает
defaultdict удобным для подсчёта (как bag или мультимножество в других
языках):
>>> s = 'mississippi'
>>> d = defaultdict(int)
>>> for k in s:
... d[k] += 1
...
>>> sorted(d.items())
[('i', 4), ('m', 1), ('p', 2), ('s', 4)]
Когда буква встречается впервые, в отображении она отсутствует, поэтому
функция default_factory вызывает int() для получения нулевого значения по умолчанию.
Затем операция инкремента наращивает счётчик для каждой буквы.
Функция int(), всегда возвращающая ноль, – это всего лишь частный случай
константных функций. Более быстрый и гибкий способ создания константных функций
– использовать лямбда-функцию, которая может возвращать любое константное значение (не только
ноль):
>>> def constant_factory(value):
... return lambda: value
...
>>> d = defaultdict(constant_factory('<missing>'))
>>> d.update(name='John', action='ran')
>>> '%(name)s %(action)s to %(object)s' % d
'John ran to <missing>'
Установка default_factory в set делает
defaultdict удобным для построения словаря множеств:
>>> s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
>>> d = defaultdict(set)
>>> for k, v in s:
... d[k].add(v)
...
>>> sorted(d.items())
[('blue', {2, 4}), ('red', {1, 3})]
namedtuple() Фабричная функция для кортежей с именованными полями¶namedtuple() Factory Function for Tuples with Named Fields
Именованные кортежи придают смысл каждой позиции в кортеже и позволяют писать более читаемый, самодокументируемый код. Их можно использовать везде, где используются обычные кортежи, и они добавляют возможность доступа к полям по имени, а не по индексу.
- collections.namedtuple(typename, field_names, *, rename=False, defaults=None, module=None)¶
Возвращает новый подкласс кортежа с именем typename. Этот подкласс используется для создания объектов, похожих на кортежи, поля которых доступны через атрибуты, а также их можно индексировать и итерировать. Экземпляры подкласса также имеют полезную строку документации (с typename и field_names) и полезный метод
__repr__(), который выводит содержимое кортежа в форматеname=value.Параметр field_names представляет собой последовательность строк, например
['x', 'y']. В качестве альтернативы field_names может быть единой строкой, в которой имена полей разделены пробелами и/или запятыми, например'x y'или'x, y'.В качестве имени поля может использоваться любой допустимый идентификатор Python, кроме имён, начинающихся с подчёркивания. Допустимые идентификаторы состоят из букв, цифр и символов подчёркивания, но не начинаются с цифры или подчёркивания и не могут быть
keyword, например class, for, return, global, pass, или raise.Если rename равен true, недопустимые имена полей автоматически заменяются позиционными именами. Например,
['abc', 'def', 'ghi', 'abc']преобразуется в['abc', '_1', 'ghi', '_3'], устраняя ключевое словоdefи дублирующееся имя поляabc.Параметр defaults может быть
Noneили итерируемым объектом значений по умолчанию. Поскольку поля со значением по умолчанию должны идти после полей без умолчания, defaults применяются к самым правым параметрам. Например, если имена полей['x', 'y', 'z'], а значения по умолчанию –(1, 2), тоxбудет обязательным аргументом,yпо умолчанию будет равно1, аz–2.Если задан параметр module, то атрибут
__module__именованного кортежа устанавливается в это значение.Экземпляры именованных кортежей не имеют собственных словарей, поэтому они легковесны и потребляют не больше памяти, чем обычные кортежи.
Для поддержки сериализации (pickle) класс именованного кортежа должен быть присвоен переменной, соответствующей typename.
Изменено в версии 3.1: Добавлена поддержка rename.
Изменено в версии 3.6: Параметры verbose и rename стали только именованными аргументами.
Изменено в версии 3.6: Добавлен параметр module.
Изменено в версии 3.7: Удалены параметр verbose и атрибут
_source.Изменено в версии 3.7: Добавлены параметр defaults и атрибут
_field_defaults.
>>> # Базовый пример
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(11, y=22) # создать экземпляр с позиционными или именованными аргументами
>>> p[0] + p[1] # доступен по индексу, как обычный кортеж (11, 22)
33
>>> x, y = p # распаковывается как обычный кортеж
>>> x, y
(11, 22)
>>> p.x + p.y # поля также доступны по имени
33
>>> p # читаемое __repr__ в стиле name=value
Point(x=11, y=22)
Именованные кортежи особенно полезны для присваивания имён полей кортежам результатов, возвращаемых
модулями csv или sqlite3:
EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')
import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))):
print(emp.name, emp.title)
import sqlite3
conn = sqlite3.connect('/companydata')
cursor = conn.cursor()
cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
for emp in map(EmployeeRecord._make, cursor.fetchall()):
print(emp.name, emp.title)
В дополнение к методам, унаследованным от кортежей, именованные кортежи поддерживают три дополнительных метода и два атрибута. Чтобы избежать конфликтов с именами полей, имена методов и атрибутов начинаются с подчёркивания.
- classmethod somenamedtuple._make(iterable, /)¶
Метод класса, который создаёт новый экземпляр из существующей последовательности или итерируемого объекта.
>>> t = [11, 22] >>> Point._make(t) Point(x=11, y=22)
- somenamedtuple._asdict()¶
Возвращает новый
dict, который отображает имена полей в соответствующие значения:>>> p = Point(x=11, y=22) >>> p._asdict() {'x': 11, 'y': 22}
Изменено в версии 3.1: Возвращает
OrderedDictвместо обычногоdict.Изменено в версии 3.8: Возвращает обычный
dictвместоOrderedDict. Начиная с Python 3.7, обычные словари гарантированно упорядочены. Если требуются дополнительные возможностиOrderedDict, рекомендуется преобразовать результат к нужному типу:OrderedDict(nt._asdict()).
- somenamedtuple._replace(**kwargs)¶
Возвращает новый экземпляр именованного кортежа, заменяя указанные поля новыми значениями:
>>> p = Point(x=11, y=22) >>> p._replace(x=33) Point(x=33, y=22) >>> for partnum, record in inventory.items(): ... inventory[partnum] = record._replace(price=newprices[partnum], timestamp=time.now())
Именованные кортежи также поддерживаются обобщённой функцией
copy.replace().Изменено в версии 3.13: Возбуждается
TypeErrorвместоValueErrorдля недопустимых именованных аргументов.
- somenamedtuple._fields¶
Кортеж строк с именами полей. Полезен для интроспекции и для создания новых типов именованных кортежей из существующих.
>>> p._fields # просмотреть имена полей ('x', 'y') >>> Color = namedtuple('Color', 'red green blue') >>> Pixel = namedtuple('Pixel', Point._fields + Color._fields) >>> Pixel(11, 22, 128, 255, 0) Pixel(x=11, y=22, red=128, green=255, blue=0)
- somenamedtuple._field_defaults¶
Словарь, отображающий имена полей в значения по умолчанию.
>>> Account = namedtuple('Account', ['type', 'balance'], defaults=[0]) >>> Account._field_defaults {'balance': 0} >>> Account('premium') Account(type='premium', balance=0)
Чтобы получить поле, имя которого хранится в строке, используйте функцию getattr()
:
>>> getattr(p, 'x')
11
Чтобы преобразовать словарь в именованный кортеж, используйте оператор двойной звёздочки (как описано в разделе Распаковка списков аргументов):
>>> d = {'x': 11, 'y': 22}
>>> Point(**d)
Point(x=11, y=22)
Поскольку именованный кортеж – это обычный класс Python, легко добавить или изменить функциональность с помощью подкласса. Вот как добавить вычисляемое поле и формат печати с фиксированной шириной:
>>> class Point(namedtuple('Point', ['x', 'y'])):
... __slots__ = ()
... @property
... def hypot(self):
... return (self.x ** 2 + self.y ** 2) ** 0.5
... def __str__(self):
... return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, self.hypot)
>>> for p in Point(3, 4), Point(14, 5/7):
... print(p)
Point: x= 3.000 y= 4.000 hypot= 5.000
Point: x=14.000 y= 0.714 hypot=14.018
Подкласс, показанный выше, устанавливает __slots__ в пустой кортеж. Это помогает
снизить требования к памяти, предотвращая создание словарей экземпляров.
Наследование не подходит для добавления новых хранимых полей. Вместо этого просто
создайте новый тип именованного кортежа из атрибута _fields:
>>> Point3D = namedtuple('Point3D', Point._fields + ('z',))
Докстринги можно настроить, напрямую присваивая значения полям __doc__
:
>>> Book = namedtuple('Book', ['id', 'title', 'authors'])
>>> Book.__doc__ += ': Hardcover book in active collection'
>>> Book.id.__doc__ = '13-digit ISBN'
>>> Book.title.__doc__ = 'Title of first printing'
>>> Book.authors.__doc__ = 'List of authors sorted by last name'
Изменено в версии 3.5: Докстринги свойств стали доступны для записи.
См. также
Смотрите
typing.NamedTupleдля способа добавления подсказок типов для именованных кортежей. Он также предоставляет элегантную запись с использованием ключевого словаclass:class Component(NamedTuple): part_number: int weight: float description: Optional[str] = None
Смотрите
types.SimpleNamespace()для изменяемого пространства имён на основе словаря вместо кортежа.Модуль
dataclassesпредоставляет декоратор и функции для автоматического добавления сгенерированных специальных методов в пользовательские классы.
OrderedDict объекты¶OrderedDict objects
Упорядоченные словари похожи на обычные словари, но имеют некоторые дополнительные
возможности, связанные с операциями упорядочивания. Они стали менее
важны, поскольку встроенный класс dict получил возможность
запоминать порядок вставки (это новое поведение стало гарантированным в
Python 3.7).
Некоторые отличия от dict всё ещё остаются:
Обычный
dictбыл спроектирован для очень хорошей работы с операциями отображения. Отслеживание порядка вставки было второстепенным.OrderedDictбыл спроектирован для хорошей работы с операциями переупорядочивания. Эффективность использования памяти, скорость итерации и производительность операций обновления были второстепенными.Алгоритм
OrderedDictможет обрабатывать частые операции переупорядочивания лучше, чемdict. Как показано в рецептах ниже, это делает его подходящим для реализации различных типов LRU-кэшей.Операция равенства для
OrderedDictпроверяет соответствие порядка.Обычный
dictможет эмулировать проверку равенства, чувствительную к порядку, с помощьюp == q and all(k1 == k2 for k1, k2 in zip(p, q)).Метод
popitem()уOrderedDictимеет другую сигнатуру. Он принимает необязательный аргумент для указания того, какой элемент извлекается.Обычный
dictможет эмулировать OrderedDict.od.popitem(last=True)с помощьюd.popitem(), который гарантированно извлекает крайний правый (последний) элемент.Обычный
dictможет эмулировать OrderedDict.od.popitem(last=False)с помощью(k := next(iter(d)), d.pop(k)), который вернёт и удалит крайний левый (первый) элемент, если он существует.У
OrderedDictесть методmove_to_end()для эффективного перемещения элемента в конечную позицию.Обычный
dictможет эмулировать OrderedDict.od.move_to_end(k, last=True)с помощьюd[k] = d.pop(k), который переместит ключ и связанное с ним значение в крайнюю правую (последнюю) позицию.У обычного
dictнет эффективного эквивалента для OrderedDict.od.move_to_end(k, last=False), который перемещает ключ и связанное с ним значение в крайнюю левую (первую) позицию.До Python 3.8 у
dictотсутствовал метод__reversed__().
- class collections.OrderedDict(**kwargs)¶
- class collections.OrderedDict(mapping, /, **kwargs)
- class collections.OrderedDict(iterable, /, **kwargs)
Возвращает экземпляр подкласса
dict, который содержит методы для перестановки порядка словаря.Добавлено в версии 3.1.
- popitem(last=True)¶
Метод
popitem()для упорядоченных словарей возвращает и удаляет пару (key, value). Пары возвращаются в порядке LIFO, если last истинно, или в порядке FIFO, если ложно.
- move_to_end(key, last=True)¶
Перемещает существующий ключ в начало или конец упорядоченного словаря. Элемент перемещается в конец, если last истинно (по умолчанию), или в начало, если last ложно. Вызывает
KeyError, если ключ не существует:>>> d = OrderedDict.fromkeys('abcde') >>> d.move_to_end('b') >>> ''.join(d) 'acdeb' >>> d.move_to_end('b', last=False) >>> ''.join(d) 'bacde'
Добавлено в версии 3.2.
Помимо обычных методов отображений, упорядоченные словари также поддерживают
обратную итерацию с помощью reversed().
Проверки на равенство между объектами OrderedDict учитывают порядок
и примерно эквивалентны list(od1.items())==list(od2.items()).
Проверки на равенство между объектами OrderedDict и другими
объектами Mapping не зависят от порядка, как и в обычных
словарях. Это позволяет подставлять объекты OrderedDict
везде, где используется обычный словарь.
Изменено в версии 3.5: Представления представления элементов, ключей и значений
объекта OrderedDict теперь поддерживают обратную итерацию с помощью reversed().
Изменено в версии 3.6: С принятием PEP 468 порядок сохраняется для именованных аргументов,
передаваемых конструктору OrderedDict и его методу update()
.
Изменено в версии 3.9: Добавлены операторы слияния (|) и обновления (|=), описанные в PEP 584.
OrderedDict Примеры и рецепты¶OrderedDict Examples and Recipes
It is straightforward to create an ordered dictionary variant that remembers the order the keys were last inserted. If a new entry overwrites an existing entry, the original insertion position is changed and moved to the end:
class LastUpdatedOrderedDict(OrderedDict):
'Store items in the order the keys were last added'
def __setitem__(self, key, value):
super().__setitem__(key, value)
self.move_to_end(key)
OrderedDict также был бы полезен для реализации
вариантов functools.lru_cache():
from collections import OrderedDict
from time import monotonic
class TimeBoundedLRU:
"LRU Cache that invalidates and refreshes old entries."
def __init__(self, func, maxsize=128, maxage=30):
self.cache = OrderedDict() # { args : (timestamp, result)}
self.func = func
self.maxsize = maxsize
self.maxage = maxage
def __call__(self, *args):
if args in self.cache:
self.cache.move_to_end(args)
timestamp, result = self.cache[args]
if monotonic() - timestamp <= self.maxage:
return result
result = self.func(*args)
self.cache[args] = monotonic(), result
if len(self.cache) > self.maxsize:
self.cache.popitem(last=False)
return result
class MultiHitLRUCache:
""" LRU-кэш, который откладывает кэширование результата, пока
он не будет запрошен несколько раз.
Чтобы избежать сброса LRU-кэша однократными запросами,
мы не кэшируем, пока запрос не будет сделан более одного раза.
"""
def __init__(self, func, maxsize=128, maxrequests=4096, cache_after=1):
self.requests = OrderedDict() # { uncached_key : request_count }
self.cache = OrderedDict() # { cached_key : function_result }
self.func = func
self.maxrequests = maxrequests # максимальное количество некэшированных запросов
self.maxsize = maxsize # максимальное количество сохранённых возвращаемых значений
self.cache_after = cache_after
def __call__(self, *args):
if args in self.cache:
self.cache.move_to_end(args)
return self.cache[args]
result = self.func(*args)
self.requests[args] = self.requests.get(args, 0) + 1
if self.requests[args] <= self.cache_after:
self.requests.move_to_end(args)
if len(self.requests) > self.maxrequests:
self.requests.popitem(last=False)
else:
self.requests.pop(args, None)
self.cache[args] = result
if len(self.cache) > self.maxsize:
self.cache.popitem(last=False)
return result
UserDict объекты¶UserDict objects
Класс UserDict действует как обёртка вокруг объектов-словарей.
Необходимость в этом классе отчасти утрачена из-за возможности
наследовать напрямую от dict; однако с ним может быть проще
работать, поскольку базовый словарь доступен как атрибут.
- class collections.UserDict(**kwargs)¶
- class collections.UserDict(mapping, /, **kwargs)
- class collections.UserDict(iterable, /, **kwargs)
Класс, который имитирует словарь. Содержимое экземпляра хранится в обычном словаре, доступном через атрибут
dataэкземпляровUserDict. Если переданы аргументы, они используются для инициализацииdata, как в обычном словаре.В дополнение к поддержке методов и операций отображений, экземпляры
UserDictпредоставляют следующий атрибут:- data¶
Реальный словарь, используемый для хранения содержимого класса
UserDict.
UserList объекты¶UserList objects
Этот класс действует как обёртка вокруг объектов-списков. Это полезный базовый класс для собственных классов, подобных спискам, которые могут наследовать от них и переопределять существующие методы или добавлять новые. Таким образом, можно добавлять новое поведение к спискам.
Необходимость в этом классе отчасти утрачена из-за возможности
наследовать напрямую от list; однако с этим классом может быть проще
работать, поскольку базовый список доступен как атрибут.
- class collections.UserList([list])¶
Класс, который имитирует список. Содержимое экземпляра хранится в обычном списке, доступном через атрибут
dataэкземпляровUserList. Содержимое экземпляра изначально устанавливается как копия list, по умолчанию – пустой список[]. list может быть любым итерируемым объектом, например настоящим списком Python или объектомUserList.В дополнение к поддержке методов и операций изменяемых последовательностей, экземпляры
UserListпредоставляют следующий атрибут:
Требования к подклассам: Ожидается, что подклассы UserList
предоставляют конструктор, который можно вызывать без аргументов или с одним
аргументом. Операции со списками, возвращающие новую последовательность, пытаются создать
экземпляр фактического класса реализации. Для этого предполагается, что конструктор
можно вызвать с одним параметром – объектом-последовательностью,
используемым как источник данных.
Если производный класс не желает соблюдать это требование, все специальные методы, поддерживаемые этим классом, должны быть переопределены; обратитесь к исходному коду за информацией о методах, которые необходимо предоставить в этом случае.
UserString объекты¶UserString objects
Класс UserString выступает в качестве обёртки для строковых объектов. Необходимость в этом классе частично отпала благодаря возможности создания подклассов непосредственно от str; однако с этим классом может быть проще работать, так как базовая строка доступна в виде атрибута.
- class collections.UserString(seq)¶
Класс, который имитирует строковый объект. Содержимое экземпляра хранится в обычном строковом объекте, доступ к которому осуществляется через атрибут
dataэкземпляровUserString. Содержимое экземпляра изначально устанавливается в копию seq. Аргумент seq может быть любым объектом, который можно преобразовать в строку с помощью встроенной функцииstr().В дополнение к поддержке методов и операций со строками, экземпляры
UserStringпредоставляют следующий атрибут:Изменено в версии 3.5: Новые методы
__getnewargs__,__rmod__,casefold,format_map,isprintableиmaketrans.