Spec-Zone.ru › Python 2.7

collections — Высокопроизводительные контейнерные типы данных

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

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

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

namedtuple()

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

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

deque

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

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

Counter

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

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

OrderedDict

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

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

defaultdict

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

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

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

1. Объекты Counter

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

>>> # Tally occurrences of words in a list
>>> cnt = Counter()
>>> for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
...     cnt[word] += 1
>>> cnt
Counter({'blue': 3, 'red': 2, 'green': 1})

>>> # Find the ten most common words in Hamlet
>>> 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 для подсчета хэшируемых объектов. Это неупорядоченное множество, где элементы хранятся в качестве ключей словаря, а их количество — в качестве значений словаря. Количество может быть любым целым числом, включая ноль или отрицательные значения.

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

>>> c = Counter()                           # a new, empty counter
>>> c = Counter('gallahad')                 # a new counter from an iterable
>>> c = Counter({'red': 4, 'blue': 2})      # a new counter from a mapping
>>> c = Counter(cats=4, dogs=8)             # a new counter from keyword args

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

>>> c = Counter(['eggs', 'ham'])
>>> c['bacon']                              # count of a missing element is zero
0

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

>>> c['sausage'] = 0                        # counter entry with a zero count
>>> del c['sausage']                        # del actually removes the entry

Новое в версии 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())                 # total of all counts
c.clear()                       # reset all counts
list(c)                         # list unique elements
set(c)                          # convert to a set
dict(c)                         # convert to a regular dictionary
c.items()                       # convert to a list of (elem, cnt) pairs
Counter(dict(list_of_pairs))    # convert from a list of (elem, cnt) pairs
c.most_common()[:-n-1:-1]       # n least common elements
c += Counter()                  # remove zero and negative counts

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

>>> c = Counter(a=3, b=1)
>>> d = Counter(a=1, b=2)
>>> c + d                       # add two counters together:  c[x] + d[x]
Counter({'a': 4, 'b': 3})
>>> c - d                       # subtract (keeping only positive counts)
Counter({'a': 2})
>>> c & d                       # intersection:  min(c[x], d[x])
Counter({'a': 1, 'b': 1})
>>> c | d                       # union:  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++ мультимножества учебное пособие с примерами.
  • Для математических операций над мультимножествами и их случаев использования см. Knuth, Donald. Искусство программирования ЭВМ, том II, раздел 4.6.3, упражнение 19.
  • Для перечисления всех различных мультимножеств заданного размера над заданным набором элементов см. itertools.combinations_with_replacement().

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

2. Объекты deque

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

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

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

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

Введено в версии 2.4.

Если maxlen не указан или равен None, deque может расти до произвольной длины. В противном случае, 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, добавив элементы из iterable. Обратите внимание, последовательность добавлений слева приводит к изменению порядка элементов в аргументе iterable.

pop()

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

popleft()

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

remove(value)

Удалить первое вхождение 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

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

Введено в версии 2.7.

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

Пример:

>>> from collections import deque
>>> d = deque('ghi')                 # make a new deque with three items
>>> for elem in d:                   # iterate over the deque's elements
...     print elem.upper()
G
H
I

>>> d.append('j')                    # add a new entry to the right side
>>> d.appendleft('f')                # add a new entry to the left side
>>> d                                # show the representation of the deque
deque(['f', 'g', 'h', 'i', 'j'])

>>> d.pop()                          # return and remove the rightmost item
'j'
>>> d.popleft()                      # return and remove the leftmost item
'f'
>>> list(d)                          # list the contents of the deque
['g', 'h', 'i']
>>> d[0]                             # peek at leftmost item
'g'
>>> d[-1]                            # peek at rightmost item
'i'

>>> list(reversed(d))                # list the contents of a deque in reverse
['i', 'h', 'g']
>>> 'h' in d                         # search the deque
True
>>> d.extend('jkl')                  # add multiple elements at once
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> d.rotate(1)                      # right rotation
>>> d
deque(['l', 'g', 'h', 'i', 'j', 'k'])
>>> d.rotate(-1)                     # left rotation
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])

>>> deque(reversed(d))               # make a new deque in reverse order
deque(['l', 'k', 'j', 'i', 'h', 'g'])
>>> d.clear()                        # empty the deque
>>> d.pop()                          # cannot pop from an empty 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() reverses the input order
>>> d
deque(['c', 'b', 'a'])

2.1. deque Рецепты

Этот раздел показывает различные подходы к работе с deque.

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

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

Другой подход к использованию deque — это поддержание последовательности недавно добавленных элементов, добавляя вправо и удаляя слева:

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 срезов и удаления. Например, чистое имплементация 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.

3. Объекты defaultdict

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, если отсутствует.

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

4. namedtuple() Функция-фабрика для кортежей с именованными полями

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

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

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

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

Любое допустимое имя Python может использоваться для имени поля, за исключением имён, начинающихся с нижнего подчёркивания. Допустимые идентификаторы состоят из букв, цифр и подчёркиваний, но не начинаются с цифры или подчёркивания и не могут быть keyword, такими как class, for, return, global, pass, print или 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)     # instantiate with positional or keyword arguments
>>> p[0] + p[1]             # indexable like the plain tuple (11, 22)
33
>>> x, y = p                # unpack like a regular tuple
>>> x, y
(11, 22)
>>> p.x + p.y               # fields also accessible by name
33
>>> p                       # readable __repr__ with a name=value style
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            # view the field names
('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.

5. OrderedDict объекты

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

class collections.OrderedDict([items])

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

Добавлена в версии 2.7.

OrderedDict.popitem(last=True)

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

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

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

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

См. также

Эквивалентный рецепт OrderedDict, который работает на Python 2.4 или более поздних версиях.

5.1. OrderedDict Примеры и рецепты

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

>>> # regular unsorted dictionary
>>> d = {'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2}

>>> # dictionary sorted by key
>>> OrderedDict(sorted(d.items(), key=lambda t: t[0]))
OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])

>>> # dictionary sorted by value
>>> OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

>>> # dictionary sorted by length of the key string
>>> 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),)

6. Абстрактные базовые классы модуля Collections

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

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(). См. также определение итератора.

class collections.Sequence
class collections.MutableSequence

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

class collections.Set
class collections.MutableSet

ABC для неизменяемых и изменяемых множеств.

END_OF_DOCUMENT_MARKER
class collections.Mapping
class collections.MutableMapping

Базовые классы для чтения и изменения отображений.

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

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

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

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

Несколько базовых классов также полезны в качестве миксинов, что облегчает разработку классов, поддерживающих контейнерные API. Например, чтобы написать класс, поддерживающий полный Set API, достаточно реализовать три абстрактных метода: __contains__(), __iter__() и __len__(). Базовый класс предоставляет остальные методы, такие как __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__() и __ge__(), тогда остальные операции будут автоматически переопределены.
  3. Миксин Set предоставляет метод _hash() для вычисления значения хеша для множества; однако, __hash__() не определен, так как не все множества хешируемы или неизменяемы. Чтобы добавить хеширование множеств с помощью миксинов, унаследуйте от Set() и Hashable(), а затем определите __hash__ = Set._hash.

См. также

  • Рецепт OrderedSet для примера, построенного на MutableSet.
  • Для получения дополнительной информации о базовых классах см. модуль abc и PEP 3119.

© 2001–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/2.7/library/collections.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API