collections
— Контейнерные типы данных¶
Исходный код: Lib/collections/__init__.py.
Этот модуль реализует специализированные типы данных контейнеров, которые являются альтернативой встроенным контейнерам общего назначения Python, dict
, list
, set
и tuple
.
фабричная функция для создания подклассов кортежей с именованными полями |
|
контейнер, похожий на список, с быстрым добавлением и выпадением с обеих сторон |
|
диктоподобный класс для создания единого представления нескольких отображений |
|
подкласс dict для подсчета хэшируемых объектов |
|
подкласс dict, который запоминает порядок добавления записей |
|
подкласс dict, который вызывает функцию фабрики для предоставления недостающих значений |
|
обертка вокруг объектов словаря для упрощения подклассификации диктов |
|
обертка вокруг объектов списка для упрощения подклассификации списков |
|
обертка вокруг строковых объектов для упрощения подклассификации строк |
ChainMap
объекты¶
Добавлено в версии 3.3.
Класс ChainMap
предназначен для быстрого связывания нескольких отображений, чтобы их можно было рассматривать как единое целое. Это часто намного быстрее, чем создание нового словаря и выполнение нескольких вызовов update()
.
Класс может быть использован для имитации вложенных диапазонов и полезен в шаблонизаторе.
-
class
collections.
ChainMap
(*maps)¶ ChainMap
группирует несколько словарей или других отображений вместе для создания единого обновляемого представления. Если не указаны * отображения*, предоставляется один пустой словарь, чтобы новая цепочка всегда имела хотя бы одно отображение.Базовые отображения хранятся в списке. Этот список является публичным и может быть доступен или обновлен с помощью атрибута maps. Других состояний нет.
При поиске последовательно перебираются базовые отображения, пока не будет найден ключ. В отличие от этого, записи, обновления и удаления работают только с первым отображением.
В
ChainMap
включены базовые отображения по ссылке. Таким образом, если одно из базовых отображений будет обновлено, эти изменения будут отражены вChainMap
.Поддерживаются все обычные методы словарей. Кроме того, имеется атрибут maps, метод для создания новых подконтекстов и свойство для доступа ко всем отображениям, кроме первого:
-
maps
¶ Обновляемый пользователем список отображений. Список упорядочен от первого к последнему. Он является единственным хранимым состоянием и может быть изменен для изменения того, какие отображения ищутся. Список всегда должен содержать хотя бы одно отображение.
-
new_child
(m=None, **kwargs)¶ Возвращает новую дикту
ChainMap
, содержащую новую карту, за которой следуют все карты текущего экземпляра. Если указаноm
, то это становится новой картой в начале списка отображений; если не указано, то используется пустой dict, так что вызовd.new_child()
эквивалентен:ChainMap({}, *d.maps)
. Если указаны какие-либо ключевые аргументы, то они обновляют переданную карту или новый пустой dict. Этот метод используется для создания подконтекстов, которые могут быть обновлены без изменения значений в родительских отображениях.Изменено в версии 3.4: Добавлен необязательный параметр
m
.Изменено в версии 3.10: Добавлена поддержка аргументов ключевых слов.
-
parents
¶ Свойство, возвращающее новое
ChainMap
, содержащее все карты в текущем экземпляре, кроме первой. Это полезно для пропуска первой карты в поиске. Случаи использования аналогичны случаям использования ключевого словаnonlocal
, используемого в nested scopes. Случаи использования также параллельны случаям использования встроенной функции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']
Изменено в версии 3.9: Добавлена поддержка операторов
|
и|=
, указанных в PEP 584.-
См.также
Параметр MultiContext class в Enthought CodeTools package имеет опции для поддержки записи в любое отображение в цепочке.
В Django Context class для шаблонов используется цепочка отображений, доступная только для чтения. В нем также есть функции выталкивания и выпрыгивания контекстов, аналогичные методу
new_child()
и свойствуparents
.Nested Contexts recipe имеет опции для управления тем, применяются ли записи и другие мутации только к первому отображению или ко всем отображениям в цепочке.
ChainMap
Примеры и рецепты¶
В этом разделе показаны различные подходы к работе с цепочками карт.
Пример моделирования внутренней цепочки поиска 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() # Create root context
d = c.new_child() # Create nested child context
e = c.new_child() # Child of c, independent from d
e.maps[0] # Current context dictionary -- like Python's locals()
e.maps[-1] # Root context -- like Python's globals()
e.parents # Enclosing context chain -- like Python's nonlocals
d['x'] = 1 # Set value in current context
d['x'] # Get first key in the chain of contexts
del d['x'] # Delete from current context
list(d) # All nested values
k in d # Check all nested values
len(d) # Number of nested values
d.items() # All nested items
dict(d) # Flatten into a regular dictionary
Класс 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' # update an existing key two levels down
>>> d['snake'] = 'red' # new keys get added to the topmost dict
>>> del d['elephant'] # remove an existing key one level down
>>> d # display result
DeepChainMap({'zebra': 'black', 'snake': 'red'}, {}, {'lion': 'orange'})
Counter
объекты¶
Для удобного и быстрого подсчета голосов предусмотрен инструмент счетчика. Например:
>>> # Tally occurrences of words in a list
>>> cnt = Counter()
>>> for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
... cnt[word] += 1
>>> cnt
Counter({'blue': 3, 'red': 2, 'green': 1})
>>> # Find the ten most common words in Hamlet
>>> 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
([iterable-or-mapping])¶ Counter
- это подклассdict
для подсчета хешируемых объектов. Это коллекция, в которой элементы хранятся в виде ключей словаря, а их количество - в виде значений словаря. Счетчики могут быть любыми целыми значениями, включая нулевые или отрицательные счетчики. КлассCounter
похож на мешки или мультинаборы в других языках.Элементы считаются из iterable или инициализируются из другого mapping (или счетчика):
>>> c = Counter() # a new, empty counter >>> c = Counter('gallahad') # a new counter from an iterable >>> c = Counter({'red': 4, 'blue': 2}) # a new counter from a mapping >>> c = Counter(cats=4, dogs=8) # a new counter from keyword args
Объекты счетчика имеют интерфейс словаря, за исключением того, что они возвращают нулевой счетчик для отсутствующих элементов, а не выдают ошибку
KeyError
:>>> c = Counter(['eggs', 'ham']) >>> c['bacon'] # count of a missing element is zero 0
Установка счетчика на ноль не удаляет элемент из счетчика. Для полного удаления используйте
del
:>>> c['sausage'] = 0 # counter entry with a zero count >>> del c['sausage'] # del actually removes the entry
Добавлено в версии 3.1.
Изменено в версии 3.7: Будучи подклассом
dict
,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])¶ Возвращает список из n наиболее распространенных элементов и их количество от наиболее распространенного до наименее распространенного. Если n опущено или
None
,most_common()
возвращает все элементы в счетчике. Элементы с одинаковым количеством упорядочиваются в том порядке, в котором они встретились первыми:>>> Counter('abracadabra').most_common(3) [('a', 5), ('b', 2), ('r', 2)]
-
subtract
([iterable-or-mapping])¶ Элементы вычитаются из iterable или из другого mapping (или счетчика). Как
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
, за исключением двух, которые работают по-другому для счетчиков.-
update
([iterable-or-mapping])¶ Элементы подсчитываются из iterable или добавляются из другого mapping (или счетчика). Как
dict.update()
, но добавляет отсчеты, а не заменяет их. Кроме того, ожидается, что iterable будет последовательностью элементов, а не последовательностью пар(key, value)
.
-
Счетчики поддерживают богатые операторы сравнения для отношений равенства, подмножества и супермножества: ==
, !=
, <
, <=
, >
, >=
. Все эти тесты рассматривают отсутствующие элементы как имеющие нулевое количество, так что Counter(a=1) == Counter(a=1, b=0)
возвращает true.
Добавлено в версии 3.10: Добавлены богатые операции сравнения.
Изменено в версии 3.10: В тестах на равенство отсутствующие элементы рассматриваются как нулевые. Раньше Counter(a=3)
и Counter(a=3, b=0)
считались различными.
Общие шаблоны для работы с объектами Counter
:
c.total() # total of all counts
c.clear() # reset all counts
list(c) # list unique elements
set(c) # convert to a set
dict(c) # convert to a regular dictionary
c.items() # convert to a list of (elem, cnt) pairs
Counter(dict(list_of_pairs)) # convert from a list of (elem, cnt) pairs
c.most_common()[:-n-1:-1] # n least common elements
+c # remove zero and negative counts
Для объединения объектов Counter
с целью получения мультинаборов (счетчиков, количество которых больше нуля) предусмотрено несколько математических операций. Сложение и вычитание объединяют счетчики путем сложения или вычитания счетчиков соответствующих элементов. Пересечение и объединение возвращают минимум и максимум соответствующих счетчиков. Равенство и включение сравнивают соответствующие счетчики. Каждая операция может принимать входные данные со знаковыми значениями, но на выходе будут исключены результаты со значениями, равными нулю или меньше.
>>> c = Counter(a=3, b=1)
>>> d = Counter(a=1, b=2)
>>> c + d # add two counters together: c[x] + d[x]
Counter({'a': 4, 'b': 3})
>>> c - d # subtract (keeping only positive counts)
Counter({'a': 2})
>>> c & d # intersection: min(c[x], d[x])
Counter({'a': 1, 'b': 1})
>>> c | d # union: max(c[x], d[x])
Counter({'a': 3, 'b': 2})
>>> c == d # equality: c[x] == d[x]
False
>>> c <= d # inclusion: 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 class в Smalltalk.
Запись в Википедии для Multisets.
C++ multisets учебник с примерами.
О математических операциях над множествами и их использовании см. в Knuth, Donald. Искусство компьютерного программирования, том II, раздел 4.6.3, упражнение 19.
Для перечисления всех различных мультимножеств заданного размера над заданным множеством элементов, см.
itertools.combinations_with_replacement()
:map(Counter, combinations_with_replacement('ABC', 2)) # --> AA AB AC BB BC CC
deque
объекты¶
-
class
collections.
deque
([iterable[, maxlen]])¶ Возвращает новый объект deque, инициализированный слева направо (с помощью
append()
) данными из iterable. Если iterable не указан, новый deque будет пустым.Deques - это обобщение стеков и очередей (название произносится как «дек» и является сокращением от «двусторонняя очередь»). Deques поддерживают потокобезопасные, экономящие память добавления и удаления с любой стороны deque с примерно одинаковой производительностью O(1) в любом направлении.
Хотя объекты
list
поддерживают аналогичные операции, они оптимизированы для быстрых операций с фиксированной длиной и несут O(n) затраты на перемещение памяти для операцийpop(0)
иinsert(0, v)
, которые изменяют как размер, так и положение базового представления данных.Если maxlen не указан или равен
None
, deques может вырасти до произвольной длины. В противном случае deque ограничивается указанной максимальной длиной. Когда deque ограниченной длины заполнен, при добавлении новых элементов с противоположного конца отбрасывается соответствующее количество элементов. Деки ограниченной длины обеспечивают функциональность, аналогичную фильтруtail
в Unix. Они также полезны для отслеживания транзакций и других пулов данных, где интерес представляет только самая последняя активность.Объекты Deque поддерживают следующие методы:
-
append
(x)¶ Добавьте x к правой части deque.
-
appendleft
(x)¶ Добавьте x к левой части deque.
-
clear
()¶ Удалить все элементы из deque, оставив его с длиной 0.
-
copy
()¶ Создайте поверхностную копию deque.
Добавлено в версии 3.5.
-
count
(x)¶ Подсчитать количество элементов deque, равных x.
Добавлено в версии 3.2.
-
extend
(iterable)¶ Расширение правой части deque путем добавления элементов из аргумента iterable.
-
extendleft
(iterable)¶ Расширение левой части deque путем добавления элементов из iterable. Обратите внимание, что серия добавлений слева приводит к изменению порядка элементов в аргументе iterable.
-
index
(x[, start[, stop]])¶ Возвращает позицию x в deque (в или после индекса start и до индекса stop). Возвращает первое совпадение или выдает
ValueError
, если оно не найдено.Добавлено в версии 3.5.
-
insert
(i, x)¶ Вставьте x в deque в позицию i.
Если вставка приведет к росту ограниченного deque за пределы maxlen, будет выдано предупреждение
IndexError
.Добавлено в версии 3.5.
-
pop
()¶ Удалить и вернуть элемент из правой части deque. Если элементов нет, выдает сообщение
IndexError
.
-
popleft
()¶ Удалить и вернуть элемент из левой части deque. Если элементов нет, выдает сообщение
IndexError
.
-
remove
(value)¶ Удалить первое вхождение значения. Если оно не найдено, выдается сообщение
ValueError
.
-
reverse
()¶ Перевернуть элементы deque на месте, а затем вернуть
None
.Добавлено в версии 3.2.
-
rotate
(n=1)¶ Поверните деку на n шагов вправо. Если n отрицательно, поверните влево.
Когда deque не пуст, поворот на один шаг вправо эквивалентен
d.appendleft(d.pop())
, а поворот на один шаг влево эквивалентенd.append(d.popleft())
.
Объекты Deque также предоставляют один атрибут, доступный только для чтения:
-
maxlen
¶ Максимальный размер deque или
None
, если он не ограничен.Добавлено в версии 3.1.
-
В дополнение к вышесказанному, deques поддерживают итерацию, pickling, len(d)
, reversed(d)
, copy.copy(d)
, copy.deepcopy(d)
, проверку принадлежности с помощью оператора in
, а также ссылки на подзапись, такие как d[0]
для доступа к первому элементу. Индексированный доступ имеет скорость O(1) на обоих концах, но замедляется до O(n) в середине. Для быстрого произвольного доступа используйте списки.
Начиная с версии 3.5, deques поддерживают __add__()
, __mul__()
и __imul__()
.
Пример:
>>> from collections import deque
>>> d = deque('ghi') # make a new deque with three items
>>> for elem in d: # iterate over the deque's elements
... print(elem.upper())
G
H
I
>>> d.append('j') # add a new entry to the right side
>>> d.appendleft('f') # add a new entry to the left side
>>> d # show the representation of the deque
deque(['f', 'g', 'h', 'i', 'j'])
>>> d.pop() # return and remove the rightmost item
'j'
>>> d.popleft() # return and remove the leftmost item
'f'
>>> list(d) # list the contents of the deque
['g', 'h', 'i']
>>> d[0] # peek at leftmost item
'g'
>>> d[-1] # peek at rightmost item
'i'
>>> list(reversed(d)) # list the contents of a deque in reverse
['i', 'h', 'g']
>>> 'h' in d # search the deque
True
>>> d.extend('jkl') # add multiple elements at once
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> d.rotate(1) # right rotation
>>> d
deque(['l', 'g', 'h', 'i', 'j', 'k'])
>>> d.rotate(-1) # left rotation
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> deque(reversed(d)) # make a new deque in reverse order
deque(['l', 'k', 'j', 'i', 'h', 'g'])
>>> d.clear() # empty the deque
>>> d.pop() # cannot pop from an empty 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() reverses the input order
>>> d
deque(['c', 'b', 'a'])
deque
Рецепты¶
В этом разделе показаны различные подходы к работе с деками.
Деки ограниченной длины обеспечивают функциональность, аналогичную фильтру tail
в Unix:
def tail(filename, n=10):
'Return the last n lines of a file'
with open(filename) as f:
return deque(f, n)
Другой подход к использованию deques заключается в поддержании последовательности недавно добавленных элементов путем добавления справа и отбрасывания слева:
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 scheduler может быть реализован с входными итераторами, хранящимися в 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:
# Remove an exhausted iterator.
iterators.popleft()
Метод rotate()
обеспечивает способ реализации нарезки и удаления deque
. Например, чисто питоновская реализация del d[n]
опирается на метод rotate()
для позиционирования элементов, которые будут извлечены:
def delete_nth(d, n):
d.rotate(-n)
d.popleft()
d.rotate(n)
Для реализации нарезки deque
используйте аналогичный подход, применяя rotate()
для переноса целевого элемента в левую часть deque. Удалите старые записи с помощью popleft()
, добавьте новые записи с помощью extend()
, а затем выполните обратное вращение. С небольшими вариациями этого подхода легко реализовать такие манипуляции со стеком в стиле Forth, как dup
, drop
, swap
, over
, pick
, rot
и roll
.
defaultdict
объекты¶
-
class
collections.
defaultdict
(default_factory=None, /[, ...])¶ Возвращает новый объект типа словаря.
defaultdict
является подклассом встроенного классаdict
. Он переопределяет один метод и добавляет одну переменную экземпляра, доступную для записи. Остальная функциональность такая же, как и у классаdict
, и здесь не документируется.Первый аргумент задает начальное значение для атрибута
default_factory
; по умолчанию он равенNone
. Все остальные аргументы обрабатываются так же, как если бы они были переданы конструкторуdict
, включая аргументы ключевых слов.Объекты
defaultdict
поддерживают следующий метод в дополнение к стандартным операциямdict
:-
__missing__
(key)¶ Если атрибут
default_factory
равенNone
, то возникает исключениеKeyError
с аргументом key.Если
default_factory
не являетсяNone
, то вызывается без аргументов для предоставления значения по умолчанию для данного ключа, это значение вставляется в словарь для ключа и возвращается.Если вызов
default_factory
вызывает исключение, то это исключение передается без изменений.Этот метод вызывается методом
__getitem__()
классаdict
, когда запрошенный ключ не найден; все, что он возвращает или поднимает, затем возвращается или поднимается методом__getitem__()
.Обратите внимание, что
__missing__()
не вызывается ни для каких операций, кроме__getitem__()
. Это означает, чтоget()
будет, как и обычные словари, возвращатьNone
по умолчанию, а не использоватьdefault_factory
.
Объекты
defaultdict
поддерживают следующую переменную экземпляра:-
default_factory
¶ Этот атрибут используется методом
__missing__()
; он инициализируется от первого аргумента конструктора, если он присутствует, или отNone
, если отсутствует.
Изменено в версии 3.9: Добавлены операторы слияния (
|
) и обновления (|=
), указанные в PEP 584.-
defaultdict
Примеры¶
Используя 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
полезным для подсчета (как мешок или мультимножество в других языках):
>>> 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()
Фабричная функция для кортежей с именованными полями¶
Именованные кортежи придают смысл каждой позиции в кортеже и позволяют сделать код более читаемым и самодокументируемым. Их можно использовать везде, где используются обычные кортежи, и они добавляют возможность доступа к полям по имени, а не по индексу позиции.
-
collections.
namedtuple
(typename, field_names, *, rename=False, defaults=None, module=None)¶ Возвращает новый подкласс кортежа с именем typename. Новый подкласс используется для создания кортежеподобных объектов, поля которых доступны для поиска по атрибутам, а также индексируемы и итерируемы. Экземпляры подкласса также имеют полезную строку документации (с именами typename и field_names) и полезный метод
__repr__()
, который перечисляет содержимое кортежа в форматеname=value
.Имена полей представляют собой последовательность строк, например
['x', 'y']
. В качестве альтернативы имена_полей могут быть одной строкой с каждым именем поля, разделенным пробелами и/или запятыми, например,'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
или iterable значений по умолчанию. Поскольку поля со значением по умолчанию должны идти после любых полей без значения по умолчанию, значения по умолчанию применяются к самым правым параметрам. Например, если имена полей['x', 'y', 'z']
и значения по умолчанию(1, 2)
, тоx
будет обязательным аргументом,y
будет значением по умолчанию1
, аz
будет значением по умолчанию2
.Если определен module, то атрибут
__module__
именованного кортежа устанавливается в это значение.Экземпляры именованных кортежей не имеют словарей для каждого экземпляра, поэтому они легкие и требуют не больше памяти, чем обычные кортежи.
Для поддержки pickling именованный класс кортежа должен быть присвоен переменной, соответствующей typename.
Изменено в версии 3.1: Добавлена поддержка переименовать.
Изменено в версии 3.6: Параметры verbose и rename стали keyword-only arguments.
Изменено в версии 3.6: Добавлен параметр модуль.
Изменено в версии 3.7: Удалены параметр verbose и атрибут
_source
.Изменено в версии 3.7: Добавлены параметр defaults и атрибут
_field_defaults
.
>>> # Basic example
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(11, y=22) # instantiate with positional or keyword arguments
>>> p[0] + p[1] # indexable like the plain tuple (11, 22)
33
>>> x, y = p # unpack like a regular tuple
>>> x, y
(11, 22)
>>> p.x + p.y # fields also accessible by name
33
>>> p # readable __repr__ with a name=value style
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())
-
somenamedtuple.
_fields
¶ Кортеж строк, перечисляющих имена полей. Полезен для интроспекции и для создания новых типов именованных кортежей из существующих именованных кортежей.
>>> p._fields # view the field names ('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
объекты¶
Упорядоченные словари похожи на обычные словари, но имеют некоторые дополнительные возможности, связанные с операциями упорядочивания. Они стали менее важны теперь, когда встроенный класс 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
может эмулироватьod.popitem(last=True)
OrderedDict с помощьюd.popitem()
, который гарантированно выводит самый правый (последний) элемент.Обычный
dict
может эмулироватьod.popitem(last=False)
OrderedDict с помощью(k := next(iter(d)), d.pop(k))
, который возвращает и удаляет самый левый (первый) элемент, если он существует.OrderedDict
имеет методmove_to_end()
для эффективной перестановки элемента в конечную точку.Обычный
dict
может эмулироватьod.move_to_end(k, last=True)
OrderedDict с помощьюd[k] = d.pop(k)
, который переместит ключ и связанное с ним значение в самую правую (последнюю) позицию.Обычный
dict
не имеет эффективного эквивалента дляod.move_to_end(k, last=False)
OrderedDict, который перемещает ключ и связанное с ним значение в самую левую (первую) позицию.До Python 3.8 в
dict
отсутствовал метод__reversed__()
.
-
class
collections.
OrderedDict
([items])¶ Возвращает экземпляр подкласса
dict
, который имеет методы, специализированные для перестановки порядка словаря.Добавлено в версии 3.1.
-
popitem
(last=True)¶ Метод
popitem()
для упорядоченных словарей возвращает и удаляет пару (ключ, значение). Пары возвращаются в порядке LIFO, если last - true, или FIFO, если false.
-
move_to_end
(key, last=True)¶ Переместить существующий ключ в любой конец упорядоченного словаря. Элемент перемещается в правый конец, если last - true (по умолчанию), или в начало, если last - false. Вызывает
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: Элементы, ключи и значения views из OrderedDict
теперь поддерживают обратную итерацию с помощью reversed()
.
Изменено в версии 3.6: С принятием PEP 468 порядок сохраняется для аргументов ключевых слов, передаваемых конструктору OrderedDict
и его методу update()
.
Изменено в версии 3.9: Добавлены операторы слияния (|
) и обновления (|=
), указанные в PEP 584.
OrderedDict
Примеры и рецепты¶
Легко создать упорядоченный вариант словаря, который запоминает порядок, в котором ключи были вставлены последними. Если новая запись перезаписывает существующую запись, исходная позиция вставки изменяется и перемещается в конец:
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 time import time
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 time() - timestamp <= self.maxage:
return result
result = self.func(*args)
self.cache[args] = time(), result
if len(self.cache) > self.maxsize:
self.cache.popitem(0)
return result
class MultiHitLRUCache:
""" LRU cache that defers caching a result until
it has been requested multiple times.
To avoid flushing the LRU cache with one-time requests,
we don't cache until a request has been made more than once.
"""
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 # max number of uncached requests
self.maxsize = maxsize # max number of stored return values
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(0)
else:
self.requests.pop(args, None)
self.cache[args] = result
if len(self.cache) > self.maxsize:
self.cache.popitem(0)
return result
UserDict
объекты¶
Класс UserDict
действует как обертка вокруг объектов словаря. Необходимость в этом классе была частично вытеснена возможностью подкласса непосредственно из dict
; однако с этим классом может быть проще работать, поскольку базовый словарь доступен как атрибут.
-
class
collections.
UserDict
([initialdata])¶ Класс, имитирующий словарь. Содержимое экземпляра хранится в обычном словаре, который доступен через атрибут
data
экземпляровUserDict
. Если указана initialdata,data
инициализируется ее содержимым; обратите внимание, что ссылка на initialdata не сохраняется, что позволяет использовать ее для других целей.В дополнение к поддержке методов и операций отображений, экземпляры
UserDict
предоставляют следующий атрибут:
UserList
объекты¶
Этот класс действует как обертка вокруг объектов списка. Это полезный базовый класс для ваших собственных спископодобных классов, которые могут наследоваться от него и переопределять существующие методы или добавлять новые. Таким образом, можно добавлять новые модели поведения в списки.
Необходимость в этом классе была частично вытеснена возможностью подкласса непосредственно из list
; однако с этим классом может быть проще работать, поскольку базовый список доступен как атрибут.
-
class
collections.
UserList
([list])¶ Класс, имитирующий список. Содержимое экземпляра хранится в обычном списке, доступ к которому осуществляется через атрибут
data
экземпляровUserList
. Изначально содержимое экземпляра устанавливается в копию list, по умолчанию это пустой список[]
. list может быть любым итерабельным списком, например, настоящим списком Python или объектомUserList
.В дополнение к поддержке методов и операций изменяемых последовательностей, экземпляры
UserList
предоставляют следующий атрибут:
Требования к подклассам: Подклассы UserList
должны предлагать конструктор, который может быть вызван либо без аргументов, либо с одним аргументом. Операции со списком, которые возвращают новую последовательность, пытаются создать экземпляр реального класса реализации. Для этого предполагается, что конструктор может быть вызван с одним параметром, которым является объект последовательности, используемый в качестве источника данных.
Если производный класс не хочет соблюдать это требование, все специальные методы, поддерживаемые этим классом, должны быть переопределены; пожалуйста, обратитесь к источникам для получения информации о методах, которые должны быть предоставлены в этом случае.
UserString
объекты¶
Класс UserString
действует как обертка вокруг строковых объектов. Необходимость в этом классе была частично вытеснена возможностью подкласса непосредственно из str
; однако с этим классом может быть проще работать, поскольку базовая строка доступна как атрибут.
-
class
collections.
UserString
(seq)¶ Класс, имитирующий строковый объект. Содержимое экземпляра хранится в обычном строковом объекте, который доступен через атрибут
data
у экземпляровUserString
. Изначально содержимое экземпляра устанавливается в копию seq. Аргументом seq может быть любой объект, который может быть преобразован в строку с помощью встроенной функцииstr()
.В дополнение к поддержке методов и операций строк, экземпляры
UserString
предоставляют следующий атрибут:-
data
¶ Реальный объект
str
, используемый для хранения содержимого классаUserString
.
Изменено в версии 3.5: Новые методы
__getnewargs__
,__rmod__
,casefold
,format_map
,isprintable
иmaketrans
.-