Документация Python неофициальный перевод
Содержание страницы

8.3. collections – Высокопроизводительные контейнерные типы данныхcollections – High-performance container datatypes

Новое в версии 2.4.

Исходный код: Lib/collections.py и Lib/_abcoll.py


Этот модуль предоставляет специализированные типы данных-контейнеры в качестве альтернативы встроенным контейнерам общего назначения Python: dict, list, set и tuple.

namedtuple()

фабричная функция для создания подклассов кортежей с именованными полями

Новое в версии 2.6.

deque

контейнер, подобный списку, с быстрыми добавлением и извлечением с обоих концов

Новое в версии 2.4.

Counter

подкласс dict для подсчёта хэшируемых объектов

Новое в версии 2.7.

OrderedDict

подкласс dict, который запоминает порядок добавления записей

Новое в версии 2.7.

defaultdict

подкласс dict, который вызывает фабричную функцию для предоставления отсутствующих значений

Новое в версии 2.5.

В дополнение к конкретным классам-контейнерам, модуль collections предоставляет абстрактные базовые классы, которые можно использовать для проверки того, предоставляет ли класс определённый интерфейс, например, является ли он хешируемым или отображением.

8.3.1. Counter объектыCounter objects

Предоставляется инструмент счётчика для удобного и быстрого подсчёта. Например:

>>> # Подсчитать вхождения слов в списке
>>> cnt = Counter()
>>> for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
...     cnt[word] += 1
>>> cnt
Counter({'blue': 3, 'red': 2, 'green': 1})

>>> # Найти десять самых распространённых слов в «Гамлете»
>>> import re
>>> words = re.findall(r'\w+', open('hamlet.txt').read().lower())
>>> Counter(words).most_common(10)
[('the', 1143), ('and', 966), ('to', 762), ('of', 669), ('i', 631),
 ('you', 554),  ('a', 546), ('my', 514), ('hamlet', 471), ('in', 451)]
class collections.Counter([iterable-or-mapping])

Класс Counter является подклассом dict для подсчёта хешируемых объектов. Это неупорядоченная коллекция, в которой элементы хранятся в качестве ключей словаря, а их количество – в качестве значений словаря. Количество может быть любым целым числом, включая ноль и отрицательные значения. Класс Counter похож на мешки или мультимножества в других языках.

Элементы подсчитываются из итерируемого объекта или инициализируются из другого отображения (или счётчика):

>>> c = Counter()                           # новый пустой счётчик
>>> c = Counter('gallahad')                 # новый счётчик из итерируемого объекта
>>> c = Counter({'red': 4, 'blue': 2})      # новый счётчик из отображения
>>> c = Counter(cats=4, dogs=8)             # новый счётчик из именованных аргументов

Объекты Counter имеют интерфейс словаря, за исключением того, что они возвращают ноль для отсутствующих элементов вместо возбуждения KeyError:

>>> c = Counter(['eggs', 'ham'])
>>> c['bacon']                              # счёт отсутствующего элемента равен нулю
0

Установка количества в ноль не удаляет элемент из счётчика. Используйте del для полного удаления:

>>> c['sausage'] = 0                        # запись счётчика с нулевым значением
>>> del c['sausage']                        # del действительно удаляет запись

Новое в версии 2.7.

Объекты Counter поддерживают три метода в дополнение к тем, что доступны для всех словарей:

elements()

Возвращает итератор по элементам, повторяя каждый столько раз, сколько указано в его счётчике. Элементы возвращаются в произвольном порядке. Если счётчик элемента меньше единицы, elements() игнорирует его.

>>> c = Counter(a=4, b=2, c=0, d=-2)
>>> list(c.elements())
['a', 'a', 'a', 'a', 'b', 'b']
most_common([n])

Возвращает список из n наиболее часто встречающихся элементов и их количества, от наиболее частых к наименее частым. Если n опущено или None, most_common() возвращает все элементы счётчика. Элементы с одинаковыми количествами упорядочиваются произвольно:

>>> Counter('abracadabra').most_common(3)
[('a', 5), ('r', 2), ('b', 2)]
subtract([iterable-or-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})

Обычные методы словарей доступны для объектов Counter, за исключением двух, которые работают с счётчиками иначе.

fromkeys(iterable)

Этот метод класса не реализован для объектов Counter.

update([iterable-or-mapping])

Элементы подсчитываются из итерируемого объекта или добавляются из другого отображения (или счётчика). Как и dict.update(), но увеличивает счётчики вместо их замены. Кроме того, итерируемый объект должен быть последовательностью элементов, а не последовательностью (key, value) пар.

Типичные приёмы работы с объектами Counter:

sum(c.values())                 # сумма всех значений
c.clear()                       # сбросить все значения
list(c)                         # список уникальных элементов
set(c)                          # преобразовать в множество
dict(c)                         # преобразовать в обычный словарь
c.items()                       # преобразовать в список пар (elem, cnt)
Counter(dict(list_of_pairs))    # создать из списка пар (элемент, кол-во)
c.most_common()[:-n-1:-1]       # n наименее частых элементов
c += Counter()                  # удалить нулевые и отрицательные значения

Для объединения объектов Counter в мультимножества (счётчики с положительными количествами) предоставляется несколько математических операций. Сложение и вычитание комбинируют счётчики, складывая или вычитая количества соответствующих элементов. Пересечение и объединение возвращают минимум и максимум соответствующих количеств. Каждая операция может принимать входные данные со знаковыми количествами, но в результате будут исключены значения с нулевыми или отрицательными количествами.

>>> c = Counter(a=3, b=1)
>>> d = Counter(a=1, b=2)
>>> c + d                       # сложение двух счётчиков: c[x] + d[x]
Counter({'a': 4, 'b': 3})
>>> c - d                       # вычитание (остаются только положительные значения)
Counter({'a': 2})
>>> c & d                       # пересечение: min(c[x], d[x])
Counter({'a': 1, 'b': 1})
>>> c | d                       # объединение: max(c[x], d[x])
Counter({'a': 3, 'b': 2})

Примечание

Счётчики в первую очередь предназначены для работы с положительными целыми числами для представления текущих счётчиков; однако была предпринята осторожность, чтобы излишне не исключать варианты использования, требующие других типов или отрицательных значений. Чтобы помочь с такими вариантами, в этом разделе описаны минимальные ограничения по диапазону и типам.

  • Сам класс Counter является подклассом словаря без ограничений на ключи и значения. Значения должны быть числами, представляющими счётчики, но в поле значения можно хранить что угодно.

  • Метод most_common() требует только упорядочиваемости значений.

  • Для операций на месте, таких как c[key] += 1, тип значения должен поддерживать только сложение и вычитание. Так что дроби, числа с плавающей запятой и десятичные числа будут работать, и отрицательные значения поддерживаются. То же самое верно для update() и subtract(), которые допускают отрицательные и нулевые значения как для входных, так и для выходных данных.

  • Методы мультимножеств предназначены только для случаев использования с положительными значениями. Входные данные могут быть отрицательными или нулевыми, но создаются только выходные данные с положительными значениями. Ограничений на тип нет, но тип значения должен поддерживать сложение, вычитание и сравнение.

  • Метод elements() требует целочисленных счётчиков. Он игнорирует нулевые и отрицательные счётчики.

См. также

  • Класс Counter адаптирован для Python 2.5 и раннего рецепта Bag для Python 2.4.

  • Класс Bag в Smalltalk.

  • Статья в Википедии о мультимножествах.

  • Мультимножества в C++: учебное пособие с примерами.

  • О математических операциях над мультимножествами и их применении см. Кнут, Дональд. Искусство программирования, том II, раздел 4.6.3, упражнение 19.

  • Чтобы перечислить все различные мультимножества заданного размера из заданного набора элементов, обратитесь к itertools.combinations_with_replacement().

    map(Counter, combinations_with_replacement(‘ABC’, 2)) –> AA AB AC BB BC CC

8.3.2. deque объектыdeque objects

class collections.deque([iterable[, maxlen]])

Возвращает новый объект deque, инициализированный слева направо (с помощью append()) данными из итерируемого объекта. Если итерируемый объект не указан, новый deque пуст.

Deques представляют собой обобщение стеков и очередей (название произносится «дэк» и является сокращением от «двусторонняя очередь»). Deques поддерживают потокобезопасные и эффективные по памяти операции добавления и извлечения элементов с любого из концов очереди с примерно одинаковой производительностью O(1) в обоих направлениях.

Хотя объекты list поддерживают аналогичные операции, они оптимизированы для быстрых операций фиксированной длины и влекут за собой затраты на перемещение памяти O(n) для операций pop(0) и insert(0, v), которые изменяют как размер, так и положение базового представления данных.

Новое в версии 2.4.

Если maxlen не указан или равен None, deques могут расти до произвольной длины. В противном случае deque ограничен заданной максимальной длиной. Как только deque ограниченной длины заполняется, при добавлении новых элементов соответствующее количество элементов отбрасывается с противоположного конца. Deque с ограниченной длиной предоставляют функциональность, аналогичную фильтру tail в Unix. Они также полезны для отслеживания транзакций и других пулов данных, где интерес представляет только самая последняя активность.

Изменено в версии 2.6: Добавлен параметр maxlen.

Объекты deque поддерживают следующие методы:

append(x)

Добавляет x в правую часть deque.

appendleft(x)

Добавляет x в левую часть deque.

clear()

Удаляет все элементы из deque, после чего его длина равна 0.

count(x)

Подсчитывает количество элементов deque, равных x.

Новое в версии 2.7.

extend(iterable)

Расширяет правую часть deque, добавляя элементы из итерируемого объекта.

extendleft(iterable)

Расширяет левую часть deque, добавляя элементы из итерируемого объекта. Обратите внимание: последовательное добавление слева приводит к обращению порядка элементов в итерируемом объекте.

pop()

Удаляет и возвращает элемент из правой части deque. Если элемент отсутствует, вызывает исключение IndexError.

popleft()

Удаляет и возвращает элемент из левой части deque. Если элемент отсутствует, вызывает исключение IndexError.

remove(value)

Удаляет первое вхождение значения. Если не найдено, вызывает исключение ValueError.

Новое в версии 2.5.

reverse()

Переворачивает элементы deque на месте и возвращает None.

Новое в версии 2.7.

rotate(n=1)

Поворачивает deque на n шагов вправо. Если n отрицательно, выполняет поворот влево.

Когда deque не пуст, поворот на один шаг вправо эквивалентен d.appendleft(d.pop()), а поворот на один шаг влево – d.append(d.popleft()).

Объекты deque также предоставляют один атрибут только для чтения:

maxlen

Максимальный размер дека или None, если неограничен.

Новое в версии 2.7.

В дополнение к вышеперечисленному, двусторонние очереди поддерживают итерацию, сериализацию, len(d), reversed(d), copy.copy(d), copy.deepcopy(d), проверку принадлежности с помощью оператора in и обращения по индексу, такие как d[-1]. Доступ по индексу выполняется за O(1) на обоих концах, но замедляется до O(n) в середине. Для быстрого произвольного доступа используйте списки.

Пример:

>>> from collections import deque
>>> d = deque('ghi')                 # создать новый deque с тремя элементами
>>> for elem in d:                   # обход элементов deque
...     print elem.upper()
G
H
I

>>> d.append('j')                    # добавить новый элемент справа
>>> d.appendleft('f')                # добавить новый элемент слева
>>> d                                # показать представление deque
deque(['f', 'g', 'h', 'i', 'j'])

>>> d.pop()                          # вернуть и удалить правый элемент
'j'
>>> d.popleft()                      # вернуть и удалить левый элемент
'f'
>>> list(d)                          # вывести содержимое deque
['g', 'h', 'i']
>>> d[0]                             # посмотреть левый элемент
'g'
>>> d[-1]                            # посмотреть правый элемент
'i'

>>> list(reversed(d))                # вывести содержимое deque в обратном порядке
['i', 'h', 'g']
>>> 'h' in d                         # поиск в deque
True
>>> d.extend('jkl')                  # добавить несколько элементов за раз
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> d.rotate(1)                      # поворот вправо
>>> d
deque(['l', 'g', 'h', 'i', 'j', 'k'])
>>> d.rotate(-1)                     # поворот влево
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])

>>> deque(reversed(d))               # создать новую deque в обратном порядке
deque(['l', 'k', 'j', 'i', 'h', 'g'])
>>> d.clear()                        # очистить deque
>>> d.pop()                          # невозможно извлечь элемент из пустой deque
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in -toplevel-
    d.pop()
IndexError: pop from an empty deque

>>> d.extendleft('abc')              # extendleft() меняет порядок ввода на обратный
>>> d
deque(['c', 'b', 'a'])

8.3.2.1. deque Рецептыdeque Recipes

В этом разделе рассматриваются различные подходы к работе с деками.

Деки с ограниченной длиной предоставляют функциональность, аналогичную фильтру tail в Unix:

def tail(filename, n=10):
    'Return the last n lines of a file'
    return deque(open(filename), 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 / float(n)

Метод rotate() позволяет реализовать deque срезы и удаление. Например, чистая реализация del d[n] на Python использует метод rotate() для позиционирования элементов, которые нужно извлечь:

def delete_nth(d, n):
    d.rotate(-n)
    d.popleft()
    d.rotate(n)

To implement deque slicing, use a similar approach applying rotate() to bring a target element to the left side of the deque. Remove old entries with popleft(), add new entries with extend(), and then reverse the rotation. With minor variations on that approach, it is easy to implement Forth style stack manipulations such as dup, drop, swap, over, pick, rot, and roll.

8.3.3. defaultdict объектыdefaultdict objects

class collections.defaultdict([default_factory[, ...]])

Возвращает новый объект, похожий на словарь. defaultdict является подклассом встроенного класса dict. Он переопределяет один метод и добавляет одну изменяемую переменную экземпляра. Остальная функциональность такая же, как у класса dict, и здесь не описывается.

Первый аргумент задает начальное значение для атрибута default_factory; по умолчанию он равен None. Все остальные аргументы обрабатываются так же, как если бы они были переданы конструктору dict, включая именованные аргументы.

Новое в версии 2.5.

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, если не передан.

8.3.3.1. defaultdict Примерыdefaultdict Examples

Используя list в качестве default_factory, легко сгруппировать последовательность пар ключ-значение в словарь списков:

>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
...     d[k].append(v)
...
>>> 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)
...
>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

Установка default_factory в int делает defaultdict удобным для подсчёта (как bag или мультимножество в других языках):

>>> s = 'mississippi'
>>> d = defaultdict(int)
>>> for k in s:
...     d[k] += 1
...
>>> d.items()
[('i', 4), ('p', 2), ('s', 4), ('m', 1)]

Когда буква встречается впервые, в отображении она отсутствует, поэтому функция default_factory вызывает int() для получения нулевого значения по умолчанию. Затем операция инкремента наращивает счётчик для каждой буквы.

Функция int(), которая всегда возвращает ноль, является лишь частным случаем константных функций. Более быстрый и гибкий способ создания константных функций – использование itertools.repeat(), который может предоставлять любое константное значение (не только ноль):

>>> def constant_factory(value):
...     return itertools.repeat(value).next
>>> 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)
...
>>> d.items()
[('blue', set([2, 4])), ('red', set([1, 3]))]

8.3.4. namedtuple() Фабричная функция для кортежей с именованными полямиnamedtuple() Factory Function for Tuples with Named Fields

Именованные кортежи придают смысл каждой позиции в кортеже и позволяют писать более читаемый, самодокументируемый код. Их можно использовать везде, где используются обычные кортежи, и они добавляют возможность доступа к полям по имени, а не по индексу.

collections.namedtuple(typename, field_names[, verbose=False][, rename=False])

Возвращает новый подкласс кортежа с именем typename. Новый подкласс используется для создания объектов, подобных кортежам, поля которых доступны через атрибуты, а также поддерживают индексацию и итерацию. Экземпляры подкласса также имеют полезную docstring (с именем типа и именами полей) и полезный метод __repr__(), который выводит содержимое кортежа в формате name=value.

Параметр field_names представляет собой последовательность строк, например ['x', 'y']. В качестве альтернативы field_names может быть единой строкой, в которой имена полей разделены пробелами и/или запятыми, например 'x y' или 'x, y'.

Any valid Python identifier may be used for a fieldname except for names starting with an underscore. Valid identifiers consist of letters, digits, and underscores but do not start with a digit or underscore and cannot be a keyword such as class, for, return, global, pass, print, or raise.

Если rename равен true, недопустимые имена полей автоматически заменяются позиционными именами. Например, ['abc', 'def', 'ghi', 'abc'] преобразуется в ['abc', '_1', 'ghi', '_3'], устраняя ключевое слово def и дублирующееся имя поля abc.

Если verbose равно true, определение класса выводится непосредственно перед его созданием.

Экземпляры именованных кортежей не имеют собственных словарей, поэтому они легковесны и потребляют не больше памяти, чем обычные кортежи.

Новое в версии 2.6.

Изменено в версии 2.7: добавлена поддержка rename.

Пример:

>>> Point = namedtuple('Point', ['x', 'y'], verbose=True)
class Point(tuple):
    'Point(x, y)'

    __slots__ = ()

    _fields = ('x', 'y')

    def __new__(_cls, x, y):
        'Create new instance of Point(x, y)'
        return _tuple.__new__(_cls, (x, y))

    @classmethod
    def _make(cls, iterable, new=tuple.__new__, len=len):
        'Make a new Point object from a sequence or iterable'
        result = new(cls, iterable)
        if len(result) != 2:
            raise TypeError('Expected 2 arguments, got %d' % len(result))
        return result

    def __repr__(self):
        'Return a nicely formatted representation string'
        return 'Point(x=%r, y=%r)' % self

    def _asdict(self):
        'Return a new OrderedDict which maps field names to their values'
        return OrderedDict(zip(self._fields, self))

    def _replace(_self, **kwds):
        'Return a new Point object replacing specified fields with new values'
        result = _self._make(map(kwds.pop, ('x', 'y'), _self))
        if kwds:
            raise ValueError('Got unexpected field names: %r' % kwds.keys())
        return result

    def __getnewargs__(self):
        'Return self as a plain tuple.  Used by copy and pickle.'
        return tuple(self)

    __dict__ = _property(_asdict)

    def __getstate__(self):
        'Exclude the OrderedDict from pickling'
        pass

    x = _property(_itemgetter(0), doc='Alias for field number 0')

    y = _property(_itemgetter(1), doc='Alias for field number 1')



>>> 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()

Возвращает новый OrderedDict, который отображает имена полей в соответствующие значения:

>>> p = Point(x=11, y=22)
>>> p._asdict()
OrderedDict([('x', 11), ('y', 22)])

Изменено в версии 2.7: Возвращает OrderedDict вместо обычного dict.

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)

Чтобы получить поле, имя которого хранится в строке, используйте функцию 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',))

Значения по умолчанию могут быть реализованы с помощью _replace() для настройки экземпляра-прототипа:

>>> Account = namedtuple('Account', 'owner balance transaction_count')
>>> default_account = Account('<owner name>', 0.0, 0)
>>> johns_account = default_account._replace(owner='John')

Перечислимые константы можно реализовать с помощью именованных кортежей, но проще и эффективнее использовать простое объявление класса:

>>> Status = namedtuple('Status', 'open pending closed')._make(range(3))
>>> Status.open, Status.pending, Status.closed
(0, 1, 2)
>>> class Status:
...     open, pending, closed = range(3)

См. также

Рецепт именованного кортежа адаптирован для Python 2.4.

8.3.5. OrderedDict объектыOrderedDict objects

Упорядоченные словари работают как обычные словари, но запоминают порядок, в котором были добавлены элементы. При итерации по упорядоченному словарю элементы возвращаются в том порядке, в котором их ключи были впервые добавлены.

class collections.OrderedDict([items])

Возвращает экземпляр подкласса dict, поддерживающего обычные методы dict. OrderedDict – это словарь, который запоминает порядок, в котором ключи были впервые вставлены. Если новая запись перезаписывает существующую, исходная позиция вставки не изменяется. Удаление записи и повторная вставка переместит её в конец.

Новое в версии 2.7.

OrderedDict.popitem(last=True)

Метод popitem() для упорядоченных словарей возвращает и удаляет пару (ключ, значение). Пары возвращаются в порядке LIFO, если last равно true, или в порядке FIFO, если false.

Помимо обычных методов отображений, упорядоченные словари также поддерживают обратную итерацию с помощью reversed().

Проверки равенства между объектами OrderedDict чувствительны к порядку и реализованы как list(od1.items())==list(od2.items()). Проверки равенства между объектами OrderedDict и другими объектами Mapping нечувствительны к порядку, как обычные словари. Это позволяет подставлять объекты OrderedDict в любом месте, где используется обычный словарь.

Конструктор OrderedDict и метод update() принимают именованные аргументы, но их порядок теряется, поскольку семантика вызова функций Python передаёт именованные аргументы через обычный неупорядоченный словарь.

См. также

Эквивалентный рецепт OrderedDict , работающий на Python 2.4 или новее.

8.3.5.1. OrderedDict Примеры и рецептыOrderedDict Examples and Recipes

Поскольку упорядоченный словарь запоминает порядок вставки, его можно использовать в сочетании с сортировкой для создания отсортированного словаря:

>>> # обычный неотсортированный словарь
>>> d = {'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2}

>>> # словарь, отсортированный по ключу
>>> OrderedDict(sorted(d.items(), key=lambda t: t[0]))
OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])

>>> # словарь, отсортированный по значению
>>> OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

>>> # словарь, отсортированный по длине строки ключа
>>> OrderedDict(sorted(d.items(), key=lambda t: len(t[0])))
OrderedDict([('pear', 1), ('apple', 4), ('orange', 2), ('banana', 3)])

Новые отсортированные словари сохраняют порядок сортировки при удалении записей. Но при добавлении новых ключей они добавляются в конец, и сортировка не сохраняется.

Также несложно создать вариант упорядоченного словаря, который запоминает порядок, в котором ключи были в последний раз вставлены. Если новая запись перезаписывает существующую, исходная позиция вставки меняется и перемещается в конец:

class LastUpdatedOrderedDict(OrderedDict):
    'Store items in the order the keys were last added'

    def __setitem__(self, key, value):
        if key in self:
            del self[key]
        OrderedDict.__setitem__(self, key, value)

Упорядоченный словарь можно комбинировать с классом Counter, чтобы счётчик запоминал порядок, в котором элементы встречаются впервые:

class OrderedCounter(Counter, OrderedDict):
     'Counter that remembers the order elements are first encountered'

     def __repr__(self):
         return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))

     def __reduce__(self):
         return self.__class__, (OrderedDict(self),)

8.3.6. Абстрактные базовые классы коллекцийCollections Abstract Base Classes

Модуль collections предоставляет следующие абстрактные базовые классы:

ABC

Наследует от

Абстрактные методы

Методы-примеси

Container

__contains__

Hashable

__hash__

Iterable

__iter__

Iterator

Iterable

next

__iter__

Sized

__len__

Callable

__call__

Sequence

Sized, Iterable, Container

__getitem__, __len__

__contains__, __iter__, __reversed__, index и count

MutableSequence

Sequence

__getitem__, __setitem__, __delitem__, __len__, insert

Наследуемые методы Sequence и append, reverse, extend, pop, remove и __iadd__

Set

Sized, Iterable, Container

__contains__, __iter__, __len__

__le__, __lt__, __eq__, __ne__, __gt__, __ge__, __and__, __or__, __sub__, __xor__ и isdisjoint

MutableSet

Set

__contains__, __iter__, __len__, add, discard

Унаследованные методы Set и clear, pop, remove, __ior__, __iand__, __ixor__ и __isub__

Mapping

Sized, Iterable, Container

__getitem__, __iter__, __len__

__contains__, keys, items, values, get, __eq__ и __ne__

MutableMapping

Mapping

__getitem__, __setitem__, __delitem__, __iter__, __len__

Унаследованные методы Mapping и pop, popitem, clear, update, и setdefault

MappingView

Sized

__len__

ItemsView

MappingView, Set

__contains__, __iter__

KeysView

MappingView, Set

__contains__, __iter__

ValuesView

MappingView

__contains__, __iter__

class collections.Container
class collections.Hashable
class collections.Sized
class collections.Callable

ABC для классов, которые предоставляют соответственно методы __contains__(), __hash__(), __len__() и __call__().

class collections.Iterable

ABC для классов, которые предоставляют метод __iter__(). См. также определение итерируемого объекта.

class collections.Iterator

ABC для классов, которые предоставляют методы __iter__() и next(). См. также определение iterator.

class collections.Sequence
class collections.MutableSequence

ABC для неизменяемых и изменяемых последовательностей.

class collections.Set
class collections.MutableSet

ABC для наборов только для чтения и изменяемых наборов.

class collections.Mapping
class collections.MutableMapping

ABC для неизменяемых и изменяемых отображений.

class collections.MappingView
class collections.ItemsView
class collections.KeysView
class collections.ValuesView

ABC для представлений отображений, элементов, ключей и значений.

Эти ABC позволяют проверять, предоставляют ли классы или их экземпляры определённую функциональность, например:

size = None
if isinstance(myvar, collections.Sized):
    size = len(myvar)

Некоторые из ABC также полезны в качестве примесей, упрощающих разработку классов, поддерживающих контейнерные API. Например, чтобы написать класс, поддерживающий полный API Set, достаточно предоставить три базовых абстрактных метода: __contains__(), __iter__() и __len__(). ABC предоставляет остальные методы, такие как __and__() и isdisjoint().

class ListBasedSet(collections.Set):
     ''' Альтернативная реализация множества, ориентированная на экономию памяти, а не на скорость
         и не требующая, чтобы элементы множества были хэшируемыми. '''
     def __init__(self, iterable):
         self.elements = lst = []
         for value in iterable:
             if value not in lst:
                 lst.append(value)

     def __iter__(self):
         return iter(self.elements)

     def __contains__(self, value):
         return value in self.elements

     def __len__(self):
         return len(self.elements)

s1 = ListBasedSet('abcdef')
s2 = ListBasedSet('defghi')
overlap = s1 & s2            # Метод __and__() поддерживается автоматически

Замечания по использованию Set и MutableSet в качестве примеси:

  1. Поскольку некоторые операции над множествами создают новые множества, методам примесей по умолчанию нужен способ создавать новые экземпляры из итерируемого объекта. Предполагается, что конструктор класса имеет сигнатуру вида ClassName(iterable). Это допущение вынесено во внутренний метод класса _from_iterable(), который вызывает cls(iterable) для создания нового множества. Если примесь Set используется в классе с другой сигнатурой конструктора, потребуется переопределить _from_iterable() методом класса, который умеет создавать новые экземпляры из итерируемого аргумента.

  2. Чтобы переопределить сравнения (предположительно для скорости, так как семантика фиксирована), переопределите __le__() и __ge__(), тогда остальные операции будут автоматически им следовать.

  3. Миксин Set предоставляет метод _hash() для вычисления хеша множества; однако __hash__() не определён, так как не все множества хешируемы или неизменяемы. Чтобы добавить хешируемость множества с помощью миксинов, унаследуйте от обоих Set() и Hashable(), а затем определите __hash__ = Set._hash.

См. также

  • Рецепт OrderedSet для примера, построенного на MutableSet.

  • Для получения дополнительной информации об ABC см. модуль abc и .