Spec-Zone.ru › Python 3.9

collections — Типы контейнерных данных

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

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

namedtuple()

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

deque

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

ChainMap

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

Counter

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

OrderedDict

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

defaultdict

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

UserDict

обёртка вокруг объектов словарей для облегчения создания подклассов словарей

UserList

обёртка вокруг объектов списков для облегчения создания подклассов списков

UserString

обёртка вокруг объектов строк для облегчения создания подклассов строк

Устарело начиная с версии 3.3, будет удалено в версии 3.10: Перемещено Абстрактные базовые классы коллекций в модуль collections.abc. Для обратной совместимости они по-прежнему доступны в этом модуле до Python 3.9.

Объекты ChainMap

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

Класс ChainMap предназначен для быстрого объединения нескольких отображений, чтобы их можно было рассматривать как единое целое. Часто он значительно быстрее, чем создание нового словаря и выполнение нескольких вызовов update().

Класс может использоваться для моделирования вложенных областей видимости и полезен при шаблонизации.

class collections.ChainMap(*maps)

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

Подлежащие отображения хранятся в списке. Этот список общедоступен и может быть доступен или обновлен с помощью атрибута maps. Других состояний нет.

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

Класс ChainMap использует ссылки на подлежащие отображения. Таким образом, если одно из подлежащих отображений будет обновлено, эти изменения будут отражены в ChainMap.

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

maps

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

new_child(m=None)

Возвращает новый ChainMap, содержащий новое отображение, за которым следуют все отображения в текущем экземпляре. Если указан параметр m, он становится новым отображением в начале списка отображений; в противном случае используется пустой словарь, так что вызов d.new_child() эквивалентен: ChainMap({}, *d.maps). Этот метод используется для создания подконтекстов, которые можно обновлять, не изменяя значения в родительских отображениях.

Изменено в версии 3.4: Добавлен необязательный параметр m.

parents

Свойство, возвращающее новый ChainMap, содержащий все отображения в текущем экземпляре, кроме первого. Это полезно для пропуска первого отображения при поиске. Сценарии использования аналогичны тем, для которых используется ключевое слово nonlocal в вложенных областях видимости. Сценарии использования также аналогичны тем, для которых используется встроенная функция super(). Ссылка на d.parents эквивалентна: ChainMap(*d.maps[1:]).

Обратите внимание, что порядок итерации ChainMap() определяется сканированием отображений в обратном порядке:

>>> baseline = {'music': 'bach', 'art': 'rembrandt'}
>>> adjustments = {'art': 'van gogh', 'opera': 'carmen'}
>>> list(ChainMap(adjustments, baseline))
['music', 'art', 'opera']

Это дает тот же порядок, что и последовательность вызовов dict.update(), начиная с последнего отображения:

>>> combined = baseline.copy()
>>> combined.update(adjustments)
>>> list(combined)
['music', 'art', 'opera']

Изменено в версии 3.9: Добавлена поддержка операторов | и |=, указанных в PEP 584.

См. также

  • Класс MultiContext в пакете Enthought CodeTools имеет параметры для поддержки записи в любое отображение в цепочке.
  • Класс Context Django для шаблонизации — это только для чтения цепочка отображений. Он также имеет функции добавления и удаления контекстов, аналогичные методу new_child() и свойству parents.
  • Рецепт Nested Contexts имеет параметры для управления тем, применяются ли записи и другие изменения только к первому отображению или к любому отображению в цепочке.
  • Упрощенная версия Chainmap только для чтения.

ChainMap Примеры и рецепты

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

Пример моделирования внутренней цепочки поиска Python:

import builtins
pylookup = ChainMap(locals(), globals(), vars(builtins))

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

import os, argparse

defaults = {'color': 'red', 'user': 'guest'}

parser = argparse.ArgumentParser()
parser.add_argument('-u', '--user')
parser.add_argument('-c', '--color')
namespace = parser.parse_args()
command_line_args = {k: v for k, v in vars(namespace).items() if v is not None}

combined = ChainMap(command_line_args, os.environ, defaults)
print(combined['color'])
print(combined['user'])

Примеры использования класса ChainMap для моделирования вложенных контекстов:

c = ChainMap()        # Create root context
d = c.new_child()     # Create nested child context
e = c.new_child()     # Child of c, independent from d
e.maps[0]             # Current context dictionary -- like Python's locals()
e.maps[-1]            # Root context -- like Python's globals()
e.parents             # Enclosing context chain -- like Python's nonlocals

d['x'] = 1            # Set value in current context
d['x']                # Get first key in the chain of contexts
del d['x']            # Delete from current context
list(d)               # All nested values
k in d                # Check all nested values
len(d)                # Number of nested values
d.items()             # All nested items
dict(d)               # Flatten into a regular dictionary

Класс ChainMap обновляет (записи и удаления) только первое отображение в цепочке, в то время как поиск будет осуществляться по всей цепочке. Однако если требуется глубокое обновление и удаление, можно легко создать подкласс, который будет обновлять ключи, найденные глубже в цепочке:

class DeepChainMap(ChainMap):
    'Variant of ChainMap that allows direct updates to inner scopes'

    def __setitem__(self, key, value):
        for mapping in self.maps:
            if key in mapping:
                mapping[key] = value
                return
        self.maps[0][key] = value

    def __delitem__(self, key):
        for mapping in self.maps:
            if key in mapping:
                del mapping[key]
                return
        raise KeyError(key)

>>> d = DeepChainMap({'zebra': 'black'}, {'elephant': 'blue'}, {'lion': 'yellow'})
>>> d['lion'] = 'orange'         # update an existing key two levels down
>>> d['snake'] = 'red'           # new keys get added to the topmost dict
>>> del d['elephant']            # remove an existing key one level down
>>> d                            # display result
DeepChainMap({'zebra': 'black', 'snake': 'red'}, {}, {'lion': 'orange'})

Объекты счетчиков

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

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

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

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

Объекты счётчика имеют интерфейс словаря, за исключением того, что они возвращают нулевое значение для отсутствующих элементов вместо возбуждения 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

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

Изменено в версии 3.7: Как подкласс dict, класс Counter унаследовал возможность запоминания порядка вставки. Математические операции над объектами Counter также сохраняют порядок. Результаты упорядочиваются в соответствии с моментом первого появления элемента в левом операнде, а затем по порядку появления в правом операнде.

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

elements()

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

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

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

>>> Counter('abracadabra').most_common(3)
[('a', 5), ('b', 2), ('r', 2)]
subtract([iterable-or-mapping])

Элементы вычитаются из итерируемого объекта или из другого отображения (или счётчика). Подобно методу dict.update(), но вычитает счётчики вместо их замены. Входные и выходные данные могут быть нулевыми или отрицательными.

>>> c = Counter(a=4, b=2, c=0, d=-2)
>>> d = Counter(a=1, b=2, c=3, d=4)
>>> c.subtract(d)
>>> c
Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})

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

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

fromkeys(iterable)

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

update([iterable-or-mapping])

Элементы подсчитываются из итерируемого объекта или добавляются из другого отображения (или счётчика). Подобно методу 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                              # 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})

Унарное сложение и вычитание — это сокращения для добавления пустого счётчика или вычитания из пустого счётчика.

>>> c = Counter(a=2, b=-4)
>>> +c
Counter({'a': 2})
>>> -c
Counter({'b': 4})

Введено в версии 3.3: Добавлена поддержка унарного сложения, унарного вычитания и операций над мультимножествами на месте.

Примечание

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

  • Класс Counter сам по себе является подклассом словаря без ограничений на ключи и значения. Значения предназначены для представления чисел, но вы можете хранить что угодно в поле значения.
  • Метод most_common() требует только того, чтобы значения были упорядочиваемы.
  • Для операций на месте, таких как c[key] += 1, тип значения должен только поддерживать сложение и вычитание. Так, дроби, числа с плавающей точкой и десятичные дроби будут работать, и поддерживаются отрицательные значения. То же самое верно для update() и subtract(), которые позволяют использовать отрицательные и нулевые значения как для входных, так и для выходных данных.
  • Методы мультимножества предназначены только для случаев использования с положительными значениями. Входные данные могут быть отрицательными или нулевыми, но создаются только выходные данные с положительными значениями. Нет ограничений по типу, но тип значения должен поддерживать сложение, вычитание и сравнение.
  • Метод elements() требует целых счётчиков. Он игнорирует нулевые и отрицательные счётчики.

См. также

  • Класс Bag в Smalltalk.
  • Статья в Википедии о Мультимножествах.
  • Руководство по мультимножествам 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
    

объекты deque

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

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

Deque — обобщение стеков и очередей (название произносится как «дек» и сокращение от «двухконцевая очередь»). Deque поддерживает потокобезопасные, эффективные с точки зрения памяти добавления и удаления элементов с любой стороны deque с примерно одинаковой производительностью 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.

copy()

Создает поверхностную копию deque.

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

count(x)

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

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

extend(iterable)

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

extendleft(iterable)

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

index(x[, start[, stop]])

Возвращает позицию x в deque (в или после индекса start и перед индексом stop). Возвращает первую совпадающую запись или вызывает ValueError, если не найдено.

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

insert(i, x)

Вставляет x в deque в позицию i.

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

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

pop()

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

popleft()

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

remove(value)

Удаляет первое вхождение value. Если не найдено, поднимается ValueError.

reverse()

Инвертирует элементы deque на месте, а затем возвращает None.

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

rotate(n=1)

Поворачивает deque на n позиций вправо. Если n отрицательное, поворот влево.

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

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

maxlen

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

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

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

Начиная с версии 3.5, deques поддерживают __add__(), __mul__(), и __imul__().

Пример:

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

deque Рецепты

Этот раздел демонстрирует различные подходы к работе с deques.

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

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

Еще один подход к использованию deques — поддержание последовательности недавно добавленных элементов путем добавления вправо и удаления влево:

def moving_average(iterable, n=3):
    # moving_average([40, 30, 50, 46, 39, 44]) --> 40.0 42.0 45.0 43.0
    # http://en.wikipedia.org/wiki/Moving_average
    it = iter(iterable)
    d = deque(itertools.islice(it, n-1))
    d.appendleft(0)
    s = sum(d)
    for elem in it:
        s += elem - d.popleft()
        d.append(elem)
        yield s / n

Распределитель задач по круговому циклу может быть реализован с помощью входных итераторов, хранящихся в deque. Значения выдаются из активного итератора в позиции ноль. Если этот итератор исчерпан, его можно удалить с помощью popleft(); в противном случае его можно вернуть в конец с помощью метода rotate():

def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    iterators = deque(map(iter, iterables))
    while iterators:
        try:
            while True:
                yield next(iterators[0])
                iterators.rotate(-1)
        except StopIteration:
            # Remove an exhausted iterator.
            iterators.popleft()

Метод 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.

Объекты defaultdict

class collections.defaultdict(default_factory=None, /[, ...])

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

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

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

__missing__(key)

Если атрибут default_factory равен None, это вызывает исключение KeyError с аргументом ключ.

Если default_factory не равен None, он вызывается без аргументов, чтобы предоставить значение по умолчанию для заданного ключа. Это значение вставляется в словарь для ключа и возвращается.

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

Этот метод вызывается методом __getitem__() класса dict, когда запрашиваемый ключ не найден. Возвращаемое или генерируемое им исключение возвращается или генерируется методом __getitem__().

Обратите внимание, что __missing__() не вызывается для операций, кроме __getitem__(). Это означает, что get() будет, как и обычные словари, возвращать None в качестве значения по умолчанию, а не использовать default_factory.

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

default_factory

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

Изменено в версии 3.9: Добавлены операторы merge (|) и update (|=) , описанные в PEP 584.

defaultdict Примеры

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

>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
...     d[k].append(v)
...
>>> sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

Когда каждый ключ встречается впервые, его еще нет в отображении; поэтому запись автоматически создается с помощью функции default_factory, которая возвращает пустой list. Операция list.append() затем прикрепляет значение к новому списку. Когда ключи встречаются снова, поиск выполняется нормально (возвращается список для этого ключа), а операция list.append() добавляет еще одно значение в список. Этот метод проще и быстрее, чем эквивалентный метод с использованием dict.setdefault():

>>> d = {}
>>> for k, v in s:
...     d.setdefault(k, []).append(v)
...
>>> sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

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

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

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

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

>>> def constant_factory(value):
...     return lambda: value
>>> d = defaultdict(constant_factory('<missing>'))
>>> d.update(name='John', action='ran')
>>> '%(name)s %(action)s to %(object)s' % d
'John ran to <missing>'

Установка default_factory на set делает defaultdict полезным для создания словаря множеств:

>>> s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
>>> d = defaultdict(set)
>>> for k, v in s:
...     d[k].add(v)
...
>>> sorted(d.items())
[('blue', {2, 4}), ('red', {1, 3})]

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

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

collections.namedtuple(typename, field_names, *, rename=False, defaults=None, module=None)

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

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

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

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

defaults может быть None или итерируемым значением по умолчанию. Поскольку поля с значением по умолчанию должны следовать за любыми полями без значения по умолчанию, defaults применяются к параметрам справа. Например, если имена полей — ['x', 'y', 'z'], а значения по умолчанию — (1, 2), то x будет обязательным аргументом, y будет иметь значение по умолчанию 1, а z будет иметь значение по умолчанию 2.

Если module определен, то атрибут __module__ именованного кортежа устанавливается в это значение.

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

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

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

Изменено в версии 3.6: Параметры verbose и rename стали ключевыми аргументами.

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

Изменено в версии 3.7: Удалён параметр verbose и атрибут _source.

Изменено в версии 3.7: Добавлен параметр defaults и атрибут _field_defaults.

>>> # Basic example
>>> Point = namedtuple('Point', ['x', 'y'])
>>> 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()

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

>>> p = Point(x=11, y=22)
>>> p._asdict()
{'x': 11, 'y': 22}

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

Изменено в версии 3.8: Возвращает обычный dict вместо OrderedDict. Начиная с Python 3.7, обычные словари гарантированно упорядочены. Если требуются дополнительные функции OrderedDict, рекомендуется привести результат к нужному типу: OrderedDict(nt._asdict()).

somenamedtuple._replace(**kwargs)

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

>>> p = Point(x=11, y=22)
>>> p._replace(x=33)
Point(x=33, y=22)

>>> for partnum, record in inventory.items():
...     inventory[partnum] = record._replace(price=newprices[partnum], timestamp=time.now())
somenamedtuple._fields

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

>>> p._fields            # 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)
somenamedtuple._field_defaults

Словарь, сопоставляющий имена полей со значениями по умолчанию.

>>> Account = namedtuple('Account', ['type', 'balance'], defaults=[0])
>>> Account._field_defaults
{'balance': 0}
>>> Account('premium')
Account(type='premium', balance=0)

Для извлечения поля, имя которого хранится в строке, используйте функцию getattr():

>>> getattr(p, 'x')
11

Для преобразования словаря в именованный кортеж используйте оператор двойной звёздочки (как описано в Распаковке списков аргументов):

>>> d = {'x': 11, 'y': 22}
>>> Point(**d)
Point(x=11, y=22)

Поскольку именованный кортеж — это обычный класс Python, можно легко добавить или изменить функциональность с помощью подкласса. Вот как добавить рассчитанное поле и формат печати с фиксированной шириной:

>>> class Point(namedtuple('Point', ['x', 'y'])):
...     __slots__ = ()
...     @property
...     def hypot(self):
...         return (self.x ** 2 + self.y ** 2) ** 0.5
...     def __str__(self):
...         return 'Point: x=%6.3f  y=%6.3f  hypot=%6.3f' % (self.x, self.y, self.hypot)

>>> for p in Point(3, 4), Point(14, 5/7):
...     print(p)
Point: x= 3.000  y= 4.000  hypot= 5.000
Point: x=14.000  y= 0.714  hypot=14.018

В показанном выше подклассе __slots__ устанавливается в пустой кортеж. Это помогает поддерживать низкие требования к памяти, предотвращая создание словарей экземпляров.

Подклассы не подходят для добавления новых, сохранённых полей. Вместо этого, просто создайте новый тип именованного кортежа из атрибута _fields:

>>> Point3D = namedtuple('Point3D', Point._fields + ('z',))

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

>>> Book = namedtuple('Book', ['id', 'title', 'authors'])
>>> Book.__doc__ += ': Hardcover book in active collection'
>>> Book.id.__doc__ = '13-digit ISBN'
>>> Book.title.__doc__ = 'Title of first printing'
>>> Book.authors.__doc__ = 'List of authors sorted by last name'

Изменено в версии 3.5: Документация свойств стала доступной для записи.

См. также

  • См. typing.NamedTuple для добавления подсказок типов для именованных кортежей. Это также предоставляет элегантную запись с использованием ключевого слова class:

    class Component(NamedTuple):
        part_number: int
        weight: float
        description: Optional[str] = None
    
  • См. types.SimpleNamespace() для изменяемого пространства имён, основанного на базовом словаре вместо кортежа.
  • Модуль dataclasses предоставляет декоратор и функции для автоматического добавления сгенерированных специальных методов в пользовательские классы.

Объекты OrderedDict

Обычные словари, но с дополнительными возможностями, связанными с операциями упорядочения. Они стали менее важными, теперь встроенный класс dict получил возможность запоминать порядок вставки (это новое поведение гарантировано в Python 3.7).

Некоторые отличия от dict все еще остаются:

  • Обычный dict был разработан для эффективных операций отображения. Отслеживание порядка вставки было вторичным.
  • Класс OrderedDict был разработан для эффективных операций переупорядочения. Эффективность использования памяти, скорость итераций и производительность операций обновления были вторичными.
  • Алгоритмически OrderedDict может лучше справляться с частыми операциями переупорядочения, чем dict. Это делает его подходящим для отслеживания последних обращений (например, в кэше LRU).
  • Операция равенства для OrderedDict проверяет соответствие порядка.
  • Метод popitem() класса OrderedDict имеет другую сигнатуру. Он принимает необязательный аргумент для указания удаляемого элемента.
  • Класс OrderedDict имеет метод move_to_end() для эффективного перемещения элемента в конец.
  • До Python 3.8 в классе dict отсутствовал метод __reversed__().
class collections.OrderedDict([items])

Возвращает экземпляр подкласса dict, у которого есть методы, специализированные для изменения порядка словаря.

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

popitem(last=True)

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

move_to_end(key, last=True)

Перемещает существующий ключ в начало или конец упорядоченного словаря. Элемент перемещается в конец, если last истинно (по умолчанию), или в начало, если last ложно. Возбуждает KeyError, если ключ не существует:

>>> d = OrderedDict.fromkeys('abcde')
>>> d.move_to_end('b')
>>> ''.join(d.keys())
'acdeb'
>>> d.move_to_end('b', last=False)
>>> ''.join(d.keys())
'bacde'

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

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

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

Изменено в версии 3.5: Представления элементов, ключей и значений views класса OrderedDict теперь поддерживают обратную итерацию с использованием reversed().

Изменено в версии 3.6: С принятием PEP 468, порядок сохраняется для ключевых аргументов, передаваемых конструктору OrderedDict и его методу update().

Изменено в версии 3.9: Добавлены операторы объединения (|) и обновления (|=), описанные в PEP 584.

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

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

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

    def __setitem__(self, key, value):
        super().__setitem__(key, value)
        self.move_to_end(key)

Класс OrderedDict также будет полезен для реализации вариантов functools.lru_cache():

class LRU:

    def __init__(self, func, maxsize=128):
        self.func = func
        self.maxsize = maxsize
        self.cache = OrderedDict()

    def __call__(self, *args):
        if args in self.cache:
            value = self.cache[args]
            self.cache.move_to_end(args)
            return value
        value = self.func(*args)
        if len(self.cache) >= self.maxsize:
            self.cache.popitem(False)
        self.cache[args] = value
        return value

Объекты UserDict

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

class collections.UserDict([initialdata])

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

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

data

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

Объекты UserList

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

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

class collections.UserList([list])

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

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

data

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

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

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

Объекты UserString

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

class collections.UserString(seq)

Класс, имитирующий строковый объект. Содержимое экземпляра хранится в обычном строковом объекте, доступном через атрибут data экземпляров UserString. Содержимое экземпляра изначально устанавливается в копию seq. Аргумент seq может быть любым объектом, который можно преобразовать в строку с помощью встроенной функции str().

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

data

Действительный объект str, используемый для хранения содержимого класса UserString.

Изменено в версии 3.5: Новые методы __getnewargs__, __rmod__, casefold, format_map, isprintable, и maketrans.

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

Spec-Zone.ru

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