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

collections – Контейнерные типы данныхcollections – Container datatypes

Этот модуль реализует высокопроизводительные контейнерные типы данных. На данный момент есть два типа: deque и defaultdict, а также одна фабричная функция типа данных – namedtuple(). Кроме того, модуль предоставляет классы UserDict и UserList, которые могут быть полезны, когда непосредственное наследование от dict или list неудобно.

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

Помимо контейнеров, модуль collections предоставляет несколько ABC (абстрактных базовых классов), которые можно использовать для проверки, поддерживает ли класс определённый интерфейс, например, является ли он хешируемым или отображением. Некоторые из них также можно использовать как классы-примеси (mixin).

ABC – абстрактные базовые классыABCs - abstract base classes

Модуль collections предоставляет следующие ABC:

ABC Наследует Абстрактные методы Методы-примеси
Container   __contains__  
Hashable   __hash__  
Iterable   __iter__  
Iterator Iterable __next__ __iter__
Sized   __len__  
Callable   __call__  
Sequence Sized, Iterable, Container __getitem__ __contains__. __iter__, __reversed__. index и count
MutableSequence Sequence __setitem__ __delitem__, и insert Унаследованные методы Sequence и append, reverse, extend, pop, remove и __iadd__
Set Sized, Iterable, Container   __le__, __lt__, __eq__, __ne__, __gt__, __ge__, __and__, __or__ __sub__, __xor__ и isdisjoint
MutableSet Set add и discard Наследуемые методы Set и clear, pop, remove, __ior__, __iand__, __ixor__ и __isub__
Mapping Sized, Iterable, Container __getitem__ __contains__, keys, items, values, get, __eq__ и __ne__
MutableMapping Mapping __setitem__ и __delitem__ Наследуемые методы Mapping и pop, popitem, clear, update, и setdefault
MappingView Sized   __len__
KeysView MappingView, Set   __contains__, __iter__
ItemsView MappingView, Set   __contains__, __iter__
ValuesView MappingView   __contains__, __iter__

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

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

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

class ListBasedSet(collections.Set):
     ''' Alternate set implementation favoring space over speed
         and not requiring the set elements to be hashable. '''
     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            # The __and__() method is supported automatically

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

  1. Поскольку некоторые операции над множествами создают новые множества, методам примеси по умолчанию нужен способ создавать новые экземпляры из итерируемого объекта. Предполагается, что конструктор класса имеет сигнатуру вида ClassName(iterable). Это предположение вынесено во внутренний метод класса _from_iterable(), который вызывает cls(iterable) для создания нового множества. Если примесь Set используется в классе с другой сигнатурой конструктора, необходимо переопределить from_iterable() методом класса, который может создавать новые экземпляры из итерируемого аргумента.
  2. Чтобы переопределить операции сравнения (предположительно для скорости, так как семантика фиксирована), переопределите __le__(), и остальные операции автоматически последуют этому примеру.
  3. Примесь Set предоставляет метод _hash() для вычисления хеш-значения множества; однако __hash__() не определён, поскольку не все множества хешируемы или неизменяемы. Чтобы добавить хешируемость множеству с помощью примесей, наследуйтесь от обоих Set() и Hashable(), затем определите __hash__ = Set._hash.

(Подробнее об ABC см. модуль abc и PEP 3119.)

объекты dequedeque objects

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

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

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

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

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

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

append(x)
Добавляет x в правую часть deque.
appendleft(x)
Добавляет x в левую часть deque.
clear()
Удаляет все элементы из deque, после чего его длина равна 0.
extend(iterable)
Расширяет правую часть deque, добавляя элементы из итерируемого объекта.
extendleft(iterable)
Расширяет левую часть deque, добавляя элементы из итерируемого объекта. Обратите внимание: последовательное добавление слева приводит к обращению порядка элементов в итерируемом объекте.
pop()
Удаляет и возвращает элемент с правой стороны deque. Если элементов нет, возбуждает IndexError.
popleft()
Удаляет и возвращает элемент с левой стороны deque. Если элементов нет, возбуждает IndexError.
remove(value)
Удаляет первое вхождение value. Если не найдено, возбуждает ValueError.
rotate(n)
Поворачивает deque на n шагов вправо. Если n отрицательно, поворачивает влево. Поворот на один шаг вправо эквивалентен: d.appendleft(d.pop()).

В дополнение к вышеперечисленному, двусторонние очереди поддерживают итерацию, сериализацию, 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'])

deque Рецептыdeque Recipes

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

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

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

Чтобы реализовать срезы для deque, используйте аналогичный подход, применяя rotate() для перемещения целевого элемента к левой стороне deque. Удалите старые записи с помощью popleft(), добавьте новые с помощью extend(), а затем обратите вращение. С небольшими вариациями этого подхода легко реализовать стековые манипуляции в стиле Forth, такие как dup, drop, swap, over, pick, rot и roll.

Алгоритмы многоэтапного сокращения данных можно кратко выразить и эффективно реализовать, извлекая элементы с помощью многократных вызовов popleft(), применяя функцию сокращения и вызывая append() для добавления результата обратно в deque.

Например, построение сбалансированного бинарного дерева из вложенных списков требует объединения двух соседних узлов в один путём группировки их в список:

>>> def maketree(iterable):
...     d = deque(iterable)
...     while len(d) > 1:
...         pair = [d.popleft(), d.popleft()]
...         d.append(pair)
...     return list(d)
...
>>> print(maketree('abcdefgh'))
[[[['a', 'b'], ['c', 'd']], [['e', 'f'], ['g', 'h']]]]

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

def tail(filename, n=10):
    'Return the last n lines of a file'
    return deque(open(filename), n)

defaultdict объектыdefaultdict objects

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

Объекты defaultdict поддерживают следующую переменную экземпляра:

default_factory
Этот атрибут используется методом __missing__(); он инициализируется из первого аргумента конструктора, если он присутствует, или None, если отсутствует.

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 полезным для подсчёта (как мешок или мультимножество в других языках):

>>> 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(), которая всегда возвращает ноль, – всего лишь частный случай константных функций. Более быстрый и гибкий способ создания константных функций – использовать лямбда-функцию, которая может возвращать любое константное значение (не только ноль):

>>> 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)
...
>>> d.items()
[('blue', set([2, 4])), ('red', set([1, 3]))]

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

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

collections.namedtuple(typename, field_names[, verbose])

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

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

В качестве имени поля может использоваться любой допустимый идентификатор Python, кроме имён, начинающихся с подчёркивания. Допустимые идентификаторы состоят из букв, цифр и подчёркиваний, но не начинаются с цифры или подчёркивания и не могут быть ключевым словом, таким как class, for, return, global, pass или raise.

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

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

Пример:

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

        __slots__ = ()

        _fields = ('x', 'y')

        def __new__(cls, 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 'Point(x=%r, y=%r)' % self

        def _asdict(t):
            'Return a new dict which maps field names to their values'
            return {'x': t[0], 'y': t[1]}

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

        x = property(itemgetter(0))
        y = property(itemgetter(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)

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

somenamedtuple._make(iterable)
Метод класса, который создаёт новый экземпляр из существующей последовательности или итерируемого объекта.
>>> t = [11, 22]
>>> Point._make(t)
Point(x=11, y=22)
somenamedtuple._asdict()

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

>>> p._asdict()
{'x': 11, 'y': 22}
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.

UserDict объектыUserDict objects

Класс UserDict действует как обёртка вокруг объектов словаря. Необходимость в этом классе частично отпала благодаря возможности создавать подклассы напрямую от dict; однако с этим классом может быть проще работать, потому что базовый словарь доступен как атрибут.

class collections.UserDict([initialdata])
Класс, имитирующий словарь. Содержимое экземпляра хранится в обычном словаре, который доступен через атрибут data объектов UserDict. Если передан initialdata, то data инициализируется его содержимым; обратите внимание, что ссылка на initialdata не сохраняется, что позволяет использовать его для других целей.

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

UserDict.data
Реальный словарь, используемый для хранения содержимого класса UserDict.

UserList объектыUserList objects

Этот класс действует как обёртка вокруг объектов-списков. Это полезный базовый класс для собственных классов, подобных спискам, которые могут наследовать от них и переопределять существующие методы или добавлять новые. Таким образом, можно добавлять новое поведение к спискам.

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

class collections.UserList([list])
Класс, имитирующий список. Содержимое экземпляра хранится в обычном списке, который доступен через атрибут data объектов UserList. Содержимое экземпляра изначально устанавливается в копию list, по умолчанию пустой список []. list может быть любым итерируемым объектом, например, настоящим списком Python или объектом UserList.

В дополнение к поддержке методов и операций изменяемых последовательностей, экземпляры UserList предоставляют следующий атрибут:

UserList.data
Настоящий объект list, используемый для хранения содержимого класса UserList.

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

Если производный класс не желает соблюдать это требование, все специальные методы, поддерживаемые этим классом, должны быть переопределены; обратитесь к исходному коду за информацией о методах, которые необходимо предоставить в этом случае.

UserString объектыUserString objects

Класс UserString действует как обёртка вокруг строковых объектов. Необходимость в этом классе частично отпала благодаря возможности создавать подклассы напрямую от str; однако с этим классом может быть проще работать, потому что базовая строка доступна как атрибут.

class collections.UserString([sequence])
Класс, имитирующий строку или объект строки Unicode. Содержимое экземпляра хранится в обычном строковом объекте, который доступен через атрибут data объектов UserString. Содержимое экземпляра изначально устанавливается в копию sequence. sequence может быть экземпляром bytes, str, UserString (или подклассом) или произвольной последовательностью, которая может быть преобразована в строку с помощью встроенной функции str().