collections
— Контейнерные типы данных¶
Исходный код: Lib/collections/__init__.py
Модуль реализует специализированные контейнерные типы данных, предоставляя альтернативы
встроенным контейнерам Python общего назначения dict
, list
,
set
и tuple
.
namedtuple() |
функция фабрика для создания подклассов кортежей с именованными полями |
deque |
контейнер похожий на спискок, но с более быстрой вставкой новых элементов в оба конца |
ChainMap |
класс похожий на словарь для создания одного представления для множества отображений |
Counter |
подкласс dict для подсчета хэшируемых объектов |
OrderedDict |
подкласс словаря отслеживющий порядок ключей после их добавления |
defaultdict |
подкласс dict, вызывающий функцию фабрику для предоставления недостающих значений |
UserDict |
обёртка вокруг словарных объектов для облегчения подклассов dict |
UserList |
обёртка вокруг списочных объектов для облегчения подклассов list |
UserString |
обёртка вокруг строковых объектов для облегчения подклассов string |
Deprecated since version 3.3, will be removed in version 3.10: Перенесён Коллекции абстрактных базовых классов в модуль collections.abc
. Для
обратной совместимости, они продолжают быть видимыми в этом модуле до Python 3.9.
Объекты ChainMap
¶
Добавлено в версии 3.3.
Класс ChainMap
предусмотрен для быстрого связывания ряда
отображений, для рассматрения их как единое целое. Это намного быстрее,
чем создание нового словаря и нескольких вызовов метода update()
.
Класс может использоваться для имитации вложенных областей видимости и полезен в шаблонах.
-
class
collections.
ChainMap
(*maps)¶ ChainMap
группирует несколько словарей или других сопоставлений вместе, создав единое и обновляемое представление. Если не указано maps, один пустой словарь предоствыляется так, что новая цепь всегда имеет по крайней мере одно отображение.Базовый отображения хранятся в списке. Этот список общедоступен и может быть получен или обновлён с помощью атрибута maps. Другие состояния отсутствуют.
Поиск поиск базового отображения последовательно до тех пор, пока ключ не найден. В отличие от этого, запись, обновление и удаление работает только для первого отображения.
В
ChainMap
включает базовое сопоставления по ссылке. Так, если один из базовых отображений обновляется, эти изменения будут отражены вChainMap
.Поддерживаются все стандартные методы словаря. Кроме того, есть атрибут maps и метод для создания новых подчинённых контекстов и свойство для доступа всех, кроме первого отображения:
-
maps
¶ Список обновляемый пользователем отображений. Список упорядочен от первого найденного до последнего-найденного. Он единственный хранит состояние и может быть изменен для изменения найденных сопоставлений. Списки всегда должны содержать по крайней мере одно отображение.
-
new_child
(m=None)¶ Возвращает новый
ChainMap
, содержащее новое отображение, следующее за всеми отображениями в текущей сущности. Если указаноm
, он становится новым отображением в передней части списка отображений; если не указан, используется пустой словарь, так что вызовd.new_child()
эквивалентен:ChainMap({}, *d.maps)
. Этот метод используется для создания подконтекстов, которые могут быть обновлены, не изменяя значений любого из родительского сопоставления.Изменено в версии 3.4: Был добавлен необязательный параметр
m
.
-
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']
-
См.также
- MultiContext класс разработанный enthought пакет CodeTools реализует возможность поддерживания записи на любые отображения в цепи.
- Django класс Context
для шаблонов только для чтения цепочки отображений. Он также содержит пуш и поп контекстов
похожих на метод
new_child()
и свойствоparents
. - Рецепт вложенных контекстов реализует возможность контроллировать запись и другие изменения применяемые только к первому отображению или отображения цепей.
- Значительно упрощенная версия только для чтения Chainmap.
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() # Создать корневой контекст
d = c.new_child() # Создать вложенный дочерний контекст
e = c.new_child() # Ребенок c, независимый от d
e.maps[0] # Текущий контекстный словарь -- подобный Python locals()
e.maps[-1] # Корневой контекст -- подобный Python globals()
e.parents # Окружение контекста цепочки -- подобный Python nonlocals
d['x'] = 1 # Установить значение в текущем контексте
d['x'] # Получить первый ключ в цепочке контекстов
del d['x'] # Удалить из текущего контекста
list(d) # Все вложенные значения
k in d # Проверить все вложенные значения
len(d) # Количество вложенных значений
d.items() # Все вложенные элементы
dict(d) # Расплющить в обычный словарь
В ChainMap
класс выполняет только обновления (пишет и удаляет) первого
отображения в цепи пока поиск будет просматривать всю цепь. Однако, если требуется глубокая запись и
удаление, это легко делается подклассом, обновляющим ключи найденных в глубине цепи:
class DeepChainMap(ChainMap):
'Вариант ChainMap, позволяющий напрямую обновлять внутренние области видимости'
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
¶
Инструмент счетчик предоставляет возможность удобного и быстрого подсчета. Например:
>>> # Подсчет встречаемости слов в списке
>>> 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
([iterable-or-mapping])¶ В
Counter
является подклассомdict
для подсчета хэшируемых объектов. Это коллекции, где элементы хранятся в качестве ключей словаря и их подсчёты хранятся в виде значений словаря. Счетчики допускают любое целое число, включая ноль или отрицательные счётчики. КлассCounter
похож на мешки или мультимножества в других языках.Элементы подсчитываются от iterable или инициализиуются другим mapping (или счетчиком):
>>> c = Counter() # новый, пустой счётчик >>> c = Counter('gallahad') # новый счетчик из итерационного объекта >>> c = Counter({'red': 4, 'blue': 2}) # новый счетчик из словаря >>> c = Counter(cats=4, dogs=8) # новый счетчик из ключевых аргументов args
Счетчик объектов имеет интерфейс словаря за исключением того, что они возвращают нулевое число отсутствующих элементов вместо того, чтобы вызывать
KeyError
:>>> c = Counter(['eggs', 'ham']) >>> c['bacon'] # количество отсутствующих элементов равно нулю 0
Установка счетчика нулём не удаляет элемент из счетчика. Чтобы удалить его используется
del
:>>> c['sausage'] = 0 # запись счетчика с нулевым счетом >>> del c['sausage'] # Del фактически удаляет запись
Добавлено в версии 3.1.
Изменено в версии 3.7: As a
dict
subclass,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()
возвращает элементы all в счетчике. Элементы с равными количествами упорядочиваются в порядке первого попавшегося:>>> 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.
Обычная методы словаря доступны для
Counter
объектов, за исключением двух, которые для счетчиков работают по-другому.-
update
([iterable-or-mapping])¶ Элементы подсчитывются от iterable или добавляются в другой mapping (или счетчик). Подобен
dict.update()
, но добавляет подсчитывание вместо того, чтобы заменить их. Кроме того, iterable предполагает наличие последовательности элементов, а не последовательность пар(key, value)
.
-
Общие шаблоны для работы с объектами Counter
:
sum(c.values()) # итого по всем счётчикам
c.clear() # сбросить все счётчики
list(c) # список уникальных элементов
set(c) # конвертировать в множество
dict(c) # преобразовать в обычный словарь
c.items() # преобразовать список в (elem, cnt) пары
Counter(dict(list_of_pairs)) # конвертировать из списка (elem, cnt) пары
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]) # doctest: +SKIP
Counter({'a': 1, 'b': 1})
>>> c | d # объединение: max(c[x], d[x])
Counter({'a': 3, 'b': 2})
Унарное сложение и вычитание являются ярлыками для добавления пустого счётчика или вычитая из пустого счётчика.
>>> 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.
Статья в Wikipedia для Multisets.
C++ multisets учебник с примерами.
Для математических операций над мультимножествами и их использование, см. Knuth, Donald. The Art of Computer Programming Volume II, Section 4.6.3, Exercise 19.
Для перечисления всех различных мультимножеств определенного размера по заданному набор элементов, см.
itertools.combinations_with_replacement()
:map(Counter, combinations_with_replacement('ABC', 2)) # --> AA AB AC BB BC CC
deque
объектов¶
-
class
collections.
deque
([iterable[, maxlen]])¶ Возвращает новый объект, инициализированный двусторонней очередью (используя
append()
) с данными из iterable. Если iterable не указан, новая двухсторонняя очередь будет пустой.Двусторонние очереди являются обобщением стеков и очередей (название произносится как «дек» и является сокращением от «двухсторонняя очередь»). Поддержка двусторонней очереди потокобезопасена и является эффективным по памяти при добавлении элементов с обеих сторон с примерно одинаковой сложности O(1) в любом направлении.
Хотя объекты
list
поддерживают подобные операции, они оптимизированы для быстрых операций с фиксированной длиной и имеют О(N) затраты по перемещению в памяти дляpop(0)
и операцийinsert(0, v)
, которые меняют положение и размер базового представления данных.Если maxlen не указан или
None
, двусторонняя очередь может вырасти до произвольной длины. В противном случае, 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, добавив элементы из итерационного аргумента.
-
extendleft
(iterable)¶ Расширить левую часть deque, добавляя элементы из 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)¶ Удалить первое вхождение value. Если не нашли, поднимает
ValueError
.
-
reverse
()¶ Перевернуть элементы deque на месте, а затем вернуться
None
.Добавлено в версии 3.2.
-
rotate
(n=1)¶ Повернуть deque n шагов вправо. Если n отрицательный, повернуть налево.
Когда deque не пустой, вращение на один шаг вправо приравнивается к
d.appendleft(d.pop())
, и поворот на один шаг влево приравнивается кd.append(d.popleft())
.
Объекты deque также предоставить один атрибут только для чтения:
-
maxlen
¶ Максимальный размер deque или
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: # Перебирать элементы по очереди
... 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)) # cписок содержимого 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
рецепты¶
В этом разделе приведены различные подходы к работе с двусторонней очередью.
Ограниченная длина двусторонней очередью обеспечить функциональность,
аналогичную фильтру tail
в Unix:
def tail(filename, n=10):
'Возвращает последние n строк файла'
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
# http://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
слайсы и удаления. Например, чистая реализация Python del d[n]
опирается на rotate()
метод для установки элементов, чтобы быть очищеными:
def delete_nth(d, n):
d.rotate(-n)
d.popleft()
d.rotate(n)
Для реализации deque
слайсов, используется аналогичный подход, применяя
rotate()
, чтобы принести целевого элемента в левой стороне двухсторонней
очереди. Удалить старые записи с popleft()
, добавлять новые записи с
extend()
, а затем выполнить обратное вращение. С незначительными вариациями этот
подход, легко выполняет манипуляцией стека, например dup
,
drop
, swap
, over
, pick
, rot
, и roll
.
Объекты defaultdict
¶
-
class
collections.
defaultdict
([default_factory[, ...]])¶ Возвращает новый словарь-как объект.
defaultdict
является подклассом встроенногоdict
класса. Он переопределяет один метод и добавляет одну записываемою переменную сущности. Остальные функции такие, как дляdict
класс и здесь не рассматриваются.Первый аргумент определяет начальное значение для атрибута
default_factory
; по умолчанию онNone
. Все остальные аргументы имеют такое же значение, как если бы они были переданы в конструкторdict
, включая ключевые аргументы.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
, если отсутствуют.
-
Примеры 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
полезной для подсчета (например, пакеты или мультимножество в других языках):
>>> 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()
установив счетчик по умолчанию, равное нулю.
Операции инкремента затем увеличивает счётчик для каждой буквы.
Функция 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
.В field_names последовательность строк, таких как
['x', 'y']
. Кроме того, field_names может быть одиной строкой для каждого имени поля, разделенных пробелами и/или запятыми, например'x y'
или'x, y'
.Любой допустимый идентификатор Python может быть использован для имени поля, за исключением имёна, начинающиеся с подчеркивания. Допустимые идентификаторы состоят из букв, цифр и символов подчеркивания, но не начинаться с цифры или знака подчеркивания и не может быть
keyword
таким как class, for, return, global, pass или raise.Если rename верно, неверные поля автоматически заменяются позиционными именами. Например,
['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__
именованный кортеж становится равным этому значению.Им сущности кортежа не содержат словарей для каждого экземпляра, поэтому они лёгкие и не требуют много памяти, чем обычные кортежи.
Изменено в версии 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())
-
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
¶
Упорядоченные словари как обычные словари, но имеют некоторые дополнительные
возможности, связанные с операциями упорядочевания. Они стали менее актуальными в настоящее
время, т.к. встроенный dict
класс обрёла способность запоминать
порядок вставки (это новое поведение стало гарантировано в Python 3.7).
Некоторые отличия от dict
по-прежнему остаются:
- Регулярное
dict
был разработан, чтобы быть очень хорошим в операции сопоставления. Отслеживание упорядочевания вставки была вторична. - В
OrderedDict
был разработан, чтобы быть хорошим в операции переупорядочения. Эффективность пространства, скорость итерации и производительность операций обновления были вторичны. - Алгоритмически,
OrderedDict
может обрабатывать частые операции переупорядочения лучше, чемdict
. Это делает его пригодным для отслеживания последних доступов (например, в LRU кэш). - Операция равенства для
OrderedDict
провероки соответствия порядка. - Метод
popitem()
изOrderedDict
имеет другую сигнатуру. Он принимает необязательный аргумент, чтобы указать, какой элемент выталкивается. OrderedDict
содержитmove_to_end()
метод, чтобы эффективно переместить элемент в конечную точку.- До 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)¶ Переместить существующий key в любой конец упорядоченного словаря. Элемент перемещается в правый конец если last имеет значение true (по умолчанию) или к началу, если last является ложным. Поднимает
KeyError
если key не существует:>>> d = OrderedDict.fromkeys('abcde') >>> d.move_to_end('b') >>> ''.join(d.keys()) 'acdeb' >>> d.move_to_end('b', last=False) >>> ''.join(d.keys()) 'bacde'
Добавлено в версии 3.2.
-
В дополнение к обычным методам словарей, упорядоченные словари также поддерживают
обратной итерации, используя reversed()
.
Проверка равенства между объектами OrderedDict
чувствительны к порядоку и реализуются
как list(od1.items())==list(od2.items())
. проверка равенства между OrderedDict
объектов и других Mapping
объектов не бесчувстельны к порядку, как обычные словари. Это позволяет заменить OrderedDict
объекты, везде, где используется обычные словари.
Изменено в версии 3.5: Элементы, ключи и значения представлений
из OrderedDict
теперь поддерживают обратные
итерации, используя reversed()
.
Изменено в версии 3.6: С принятием PEP 468, порядок сохраняется на ключевые аргументы, переданных
конструктору OrderedDict
и методу update()
.
OrderedDict
примеры и рецепты¶
Создать упорядоченный вариант словаря очень просто, запомнив порядок добавления ключей последний раз. Если новая запись перезаписывает существующую запись, исходное положение курсора изменяется и перемещается в конец:
class LastUpdatedOrderedDict(OrderedDict):
'Хранить элементы в порядке последнего добавления ключей'
def __setitem__(self, key, value):
super().__setitem__(key, value)
self.move_to_end(key)
В OrderedDict
также будет полезен для реализации вариантов functools.lru_cache()
:
class LRU(OrderedDict):
'Предельный размер, вытесняющий наименьший недавно найденный ключ при заполнении'
def __init__(self, maxsize=128, /, *args, **kwds):
self.maxsize = maxsize
super().__init__(*args, **kwds)
def __getitem__(self, key):
value = super().__getitem__(key)
self.move_to_end(key)
return value
def __setitem__(self, key, value):
if key in self:
self.move_to_end(key)
super().__setitem__(key, value)
if len(self) > self.maxsize:
oldest = next(iter(self))
del self[oldest]
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
.-