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']

См.также

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 объектов, за исключением двух, которые для счетчиков работают по-другому.

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 для 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):
        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 сущности предоставляют следующие атрибуты:

data

Настоящий list объект используемый для хранения содержание 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.