collections
— Контейнерные типы данных
Модуль реализует специализированные контейнерные типы данных, предоставляя
альтернативы встроенным контейнерам Python общего назначения dict
,
list
, set
и tuple
.
namedtuple() |
функция фабрика для создания подклассов кортежей с именованными полями |
deque |
контейнер похожий на список, но с более быстрой вставкой новых элементов в оба конца |
ChainMap |
класс похожий на словарь для создания одного представления для множества отображений |
Counter |
подкласс dict для подсчёта хэшируемых объектов |
OrderedDict |
подкласс словаря отслеживающий порядок ключей после их добавления |
defaultdict |
подкласс dict, вызывающий функцию фабрику для предоставления недостающих значений |
UserDict |
обёртка вокруг словарных объектов для облегчения подклассов dict |
UserList |
обёртка вокруг списочных объектов для облегчения подклассов list |
UserString |
обёртка вокруг строковых объектов для облегчения string подклассов |
Устарело с версии 3.3, будет удалено в 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: Как подкласс
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.
Обычные методы словаря доступны для
Counter
объектов, за исключением двух, которые для счётчиков работают по-другому.-
fromkeys
(iterable) Метод класса не применяется для
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 про Мультимножества.
C++ мультимножества учебник с примерами.
Для математических операций над мультимножествами и их использование, см. 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
поддерживают аналогичные операции, они оптимизированы для быстрых операций фиксированной длины и требуют O(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') # Создать новую очередь с тремя элементами
>>> for elem in d: # Перебирать элементы по очереди
... print(elem.upper())
G
H
I
>>> d.append('j') # Добавить новую запись в правую сторону
>>> d.appendleft('f') # Добавить новую запись в левую сторону
>>> d # Показать представление двухсторонней очереди
deque(['f', 'g', 'h', 'i', 'j'])
>>> d.pop() # вернуть и удалить самый правый элемент
'j'
>>> d.popleft() # вернуть и удалить самый левый элемент
'f'
>>> list(d) # Список содержимого очереди
['g', 'h', 'i']
>>> d[0] # посмотреть на самый левый элемент
'g'
>>> d[-1] # посмотреть на самый правый элемент
'i'
>>> list(reversed(d)) # список содержимого очереди наоборот
['i', 'h', 'g']
>>> 'h' in d # поиск по очереди
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 может быть использован для имени поля, за исключением имён, начинающиеся с подчеркивания. Допустимые идентификаторы состоят из букв, цифр и символов подчеркивания, но не начинаться с цифры или знака подчёркивания и не может быть ключевым словом таким как 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 содержит истинное значение (по умолчанию) или к началу, если 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
сущности предоставляют следующие атрибуты:-
data
Используемый настоящий словарь для хранения содержимого класса
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
.-