collections — Типы контейнерных данных
Исходный код: Lib/collections/__init__.py
В этом модуле реализованы специализированные контейнерные типы данных, предоставляющие альтернативы встроенным контейнерам Python общего назначения, dict, list, set и tuple.
namedtuple() | функция-фабрика для создания подклассов кортежей с именованными полями |
deque | подобный списку контейнер с быстрыми добавлениями и удалениями элементов в начале и конце |
ChainMap | класс типа dict для создания единого представления нескольких словарей |
Counter | подкласс dict для подсчета хешируемых объектов |
OrderedDict | подкласс dict, запоминающий порядок добавления элементов |
defaultdict | подкласс dict, вызывающий функцию-фабрику для заполнения отсутствующих значений |
UserDict | обёртка вокруг объектов словарей для более простого создания подклассов словарей |
UserList | обёртка вокруг объектов списков для более простого создания подклассов списков |
UserString | обёртка вокруг объектов строк для более простого создания подклассов строк |
Изменено в версии 3.3: Перемещено Абстрактные базовые классы коллекций в модуль collections.abc. Для обратной совместимости они по-прежнему видны в этом модуле.
1. Объекты ChainMap
Новое в версии 3.3.
Класс ChainMap предназначен для быстрого объединения нескольких словарей, чтобы их можно было рассматривать как единое целое. Часто это значительно быстрее, чем создание нового словаря и выполнение нескольких вызовов update().
Класс может использоваться для имитации вложенных областей видимости и полезен при шаблонизации.
-
class collections.ChainMap(*maps) -
Класс
ChainMapобъединяет несколько словарей или других отображений, чтобы создать единое обновляемое представление. Если не указано значение maps, предоставляется единственный пустой словарь, чтобы новая цепочка всегда имела как минимум одно отображение.Базовые отображения хранятся в списке. Этот список является общедоступным и может быть изменен с помощью атрибута maps. Других состояний нет.
Обращения к ключам осуществляются последовательно по базовым отображениям, пока не будет найден ключ. Напротив, записи, обновления и удаления применяются только к первому отображению.
Класс
ChainMapвключает базовые отображения по ссылке. Таким образом, если одно из базовых отображений будет обновлено, эти изменения будут отражены вChainMap.Поддерживаются все обычные методы словарей. Кроме того, имеется атрибут maps, метод для создания новых подконтекстов и свойство для доступа ко всем отображениям, кроме первого:
-
maps -
Обновляемый пользователем список отображений. Список отсортирован от первого к последнему искомому отображению. Он является единственным хранимым состоянием и может быть изменен для изменения порядка поиска отображений. Список должен всегда содержать как минимум одно отображение.
-
new_child(m=None) -
Возвращает новый объект
ChainMap, содержащий новое отображение, а за ним — все отображения текущего экземпляра. Если значение map указано, оно становится новым отображением в начале списка отображений; в противном случае используется пустой словарь, так что вызовd.new_child()эквивалентен:ChainMap({}, *d.maps). Этот метод используется для создания подконтекстов, которые можно обновлять без изменения значений в родительских отображениях.Изменено в версии 3.4: Добавлен необязательный параметр
m.
-
parents -
Свойство, возвращающее новый объект
ChainMap, содержащий все отображения текущего экземпляра, кроме первого. Это полезно для пропуска первого отображения при поиске. Сценарии использования аналогичны тем, которые используют ключевое словоnonlocalв вложенных областях видимости. Сценарии использования также аналогичны тем, которые используются для встроенной функцииsuper(). Ссылка наd.parentsэквивалентна:ChainMap(*d.maps[1:]).
-
См. также
- Класс MultiContext в пакете Enthought CodeTools имеет возможности поддержки записи в любое отображение в цепочке.
- Класс Context Django для шаблонизации — это только для чтения цепочка отображений. Он также имеет функции добавления и удаления контекстов, аналогичные методу
new_child()и свойствуparents(). - Рецепт вложенных контекстов имеет возможности управления тем, применяются ли записи и другие изменения только к первому отображению или ко всем отображениям в цепочке.
- Очень упрощенная версия Chainmap только для чтения.
1.1. Примеры и рецепты 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}
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'] # Get first key in the chain of contexts d['x'] = 1 # Set value in current context 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
DeepChainMap({'zebra': 'black', 'snake': 'red'}, {}, {'lion': 'orange'})
2. Объекты 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]) -
A
Counteris adictsubclass for counting hashable objects. It is an unordered collection where elements are stored as dictionary keys and their counts are stored as dictionary values. Counts are allowed to be any integer value including zero or negative counts. TheCounterclass is similar to bags or multisets in other languages.Elements are counted from an iterable or initialized from another mapping (or 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 argsCounter objects have a dictionary interface except that they return a zero count for missing items instead of raising a
KeyError:>>> c = Counter(['eggs', 'ham']) >>> c['bacon'] # count of a missing element is zero 0
Setting a count to zero does not remove an element from a counter. Use
delto remove it entirely:>>> c['sausage'] = 0 # counter entry with a zero count >>> del c['sausage'] # del actually removes the entry
New in version 3.1.
Counter objects support three methods beyond those available for all dictionaries:
-
elements() -
Return an iterator over elements repeating each as many times as its count. Elements are returned in arbitrary order. If an element’s count is less than one,
elements()will ignore it.>>> c = Counter(a=4, b=2, c=0, d=-2) >>> sorted(c.elements()) ['a', 'a', 'a', 'a', 'b', 'b']
-
most_common([n]) -
Return a list of the n most common elements and their counts from the most common to the least. If n is omitted or
None,most_common()returns all elements in the counter. Elements with equal counts are ordered arbitrarily:>>> Counter('abracadabra').most_common(3) # doctest: +SKIP [('a', 5), ('r', 2), ('b', 2)]
-
subtract([iterable-or-mapping]) -
Elements are subtracted from an iterable or from another mapping (or counter). Like
dict.update()but subtracts counts instead of replacing them. Both inputs and outputs may be zero or negative.>>> 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})New in version 3.2.
The usual dictionary methods are available for
Counterobjects except for two which work differently for counters.-
fromkeys(iterable) -
This class method is not implemented for
Counterobjects.
-
update([iterable-or-mapping]) -
Elements are counted from an iterable or added-in from another mapping (or counter). Like
dict.update()but adds counts instead of replacing them. Also, the iterable is expected to be a sequence of elements, not a sequence of(key, value)pairs.
-
Common patterns for working with Counter objects:
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
Several mathematical operations are provided for combining Counter objects to produce multisets (counters that have counts greater than zero). Addition and subtraction combine counters by adding or subtracting the counts of corresponding elements. Intersection and union return the minimum and maximum of corresponding counts. Each operation can accept inputs with signed counts, but the output will exclude results with counts of zero or less.
>>> 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]) # doctest: +SKIP
Counter({'a': 1, 'b': 1})
>>> c | d # union: max(c[x], d[x])
Counter({'a': 3, 'b': 2})
Unary addition and subtraction are shortcuts for adding an empty counter or subtracting from an empty counter.
>>> c = Counter(a=2, b=-4)
>>> +c
Counter({'a': 2})
>>> -c
Counter({'b': 4})
New in version 3.3: Added support for unary plus, unary minus, and in-place multiset operations.
Примечание
Счётчики были разработаны в первую очередь для работы с положительными целыми числами для представления текущих подсчётов; однако, было предпринято внимание, чтобы не исключать излишне случаи использования, требующие других типов или отрицательных значений. Чтобы помочь с этими случаями использования, в этом разделе документированы минимальные ограничения диапазона и типа.
- Класс
Counterсам по себе является подклассом словаря без ограничений на его ключи и значения. Значения предназначены для того, чтобы быть числами, представляющими счётчики, но вы можете хранить что угодно в поле значения. - Метод
most_common()требует только того, чтобы значения были упорядочиваемы. - Для операций на месте, таких как
c[key] += 1, тип значения должен только поддерживать сложение и вычитание. Так дроби, числа с плавающей точкой и десятичные дроби будут работать, и поддерживаются отрицательные значения. То же самое относится кupdate()иsubtract(), которые допускают отрицательные и нулевые значения как для входных, так и для выходных данных. - Методы мультимножества разработаны только для случаев использования с положительными значениями. Входные данные могут быть отрицательными или нулевыми, но только выходные данные с положительными значениями создаются. Нет ограничений на тип, но тип значения должен поддерживать сложение, вычитание и сравнение.
- Метод
elements()требует целочисленных счётчиков. Он игнорирует нулевые и отрицательные счётчики.
См. также
- Класс Bag в Smalltalk.
- Статья Википедии о Мультимножествах.
- C++ multisets tutorial с примерами.
- Для математических операций над мультимножествами и их случаев использования см. Knuth, Donald. The Art of Computer Programming Volume II, Section 4.6.3, Exercise 19.
-
Чтобы перечислить все различные мультимножества заданного размера над заданным набором элементов, см.
itertools.combinations_with_replacement():map(Counter, combinations_with_replacement(‘ABC’, 2)) –> AA AB AC BB BC CC
3. deque объектов
-
class collections.deque([iterable[, maxlen]]) -
Возвращает новый объект deque, инициализированный слева направо (используя
append()) данными из iterable. Если iterable не указан, новый deque пустой.Deques — обобщение стеков и очередей (название произносится как «дек» и является сокращением от «двухсторонней очереди»). Deques поддерживают потокобезопасные, эффективные по памяти добавления и извлечения элементов с любой стороны deque с примерно одинаковой производительностью O(1) в любом направлении.
Хотя объекты
listподдерживают аналогичные операции, они оптимизированы для быстрых операций с фиксированной длиной и несут расходы O(n) на перемещение памяти для операцийpop(0)иinsert(0, v), которые изменяют как размер, так и позицию базового представления данных.Если maxlen не указан или равен
None, deque может расти до произвольной длины. В противном случае deque ограничен указанной максимальной длиной. После того как deque ограниченной длины заполнится, при добавлении новых элементов соответствующее количество элементов удаляется с противоположного конца. Deques ограниченной длины предоставляют функциональность, аналогичную фильтруtailв Unix. Они также полезны для отслеживания транзакций и других наборов данных, где интерес представляет только самая последняя активность.Объекты Deque поддерживают следующие методы:
-
append(x) -
Добавить x в правую часть deque.
-
appendleft(x) -
Добавить x в левую часть deque.
-
clear() -
Удалить все элементы из deque, оставив его длину равной 0.
-
copy() -
Создать поверхностную копию deque.
Введено в версии 3.5.
-
count(x) -
Подсчитать количество элементов deque, равных x.
Введено в версии 3.2.
-
extend(iterable) -
Расширить правую часть deque, добавляя элементы из итерируемого аргумента.
-
extendleft(iterable) -
Расширить левую часть deque, добавляя элементы из iterable. Обратите внимание, последовательность добавлений слева приводит к изменению порядка элементов в аргументе 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) -
Повернуть deque на n шагов вправо. Если n отрицательное, повернуть влево. Поворот на один шаг вправо эквивалентен:
d.appendleft(d.pop()).
Объекты Deque также предоставляют одно только для чтения атрибут:
-
maxlen -
Максимальный размер deque или
Noneесли он неограничен.Введено в версии 3.1.
-
Помимо вышеперечисленного, deques поддерживают итерацию, сериализацию, len(d), reversed(d), copy.copy(d), copy.deepcopy(d), проверку на вхождение с помощью оператора in и ссылки по индексу, такие как d[-1]. Доступ по индексу — 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'])
3.1. deque Рецепты
В этом разделе показаны различные подходы к работе с deques.
Deques ограниченной длины обеспечивают функциональность, аналогичную фильтру 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
Метод 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.
4. defaultdict objects
-
class collections.defaultdict([default_factory[, ...]]) -
Возвращает новый объект, похожий на словарь.
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, если его нет.
-
4.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)
...
>>> 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(), чтобы обеспечить значение по умолчанию 0. Операция инкремента затем наращивает счёт для каждой буквы.
Функция 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})]
5. namedtuple() — Функция-фабрика для кортежей с именованными полями
Именованные кортежи присваивают значение каждой позиции в кортеже и позволяют писать более понятный и документированный код. Их можно использовать везде, где используются обычные кортежи, и они добавляют возможность доступа к полям по имени вместо индекса позиции.
-
collections.namedtuple(typename, field_names, verbose=False, rename=False) -
Возвращает новый подкласс кортежа с именем typename. Новый подкласс используется для создания объектов, похожих на кортежи, которые имеют доступ к полям с помощью поиска по атрибуту, а также индексируются и итерируются. Экземпляры подкласса также имеют полезную строку документации (с typename и field_names) и полезный метод
__repr__(), который выводит содержимое кортежа в форматеname=value.field_names — это строка, в которой каждое имя поля отделяется пробелами и/или запятыми, например,
'x y'или'x, y'. В качестве альтернативы, field_names может быть последовательностью строк, например,['x', 'y'].Любое допустимое имя Python может использоваться для имени поля, за исключением имён, начинающихся с нижнего подчёркивания. Допустимые идентификаторы состоят из букв, цифр и подчёркиваний, но не начинаются с цифры или подчёркивания и не являются ключевыми словами Python, такими как class, for, return, global, pass или raise.
Если rename равно True, недопустимые имена полей автоматически заменяются позиционными именами. Например,
['abc', 'def', 'ghi', 'abc']преобразуется в['abc', '_1', 'ghi', '_3'], исключая ключевое словоdefи дублируемое имя поляabc.Если verbose равно True, определение класса печатается после его создания. Этот параметр устарел; вместо этого проще напечатать атрибут
_source.Экземпляры именованных кортежей не имеют словарей по экземплярам, поэтому они лёгкие и не требуют больше памяти, чем обычные кортежи.
Изменено в версии 3.1: Добавлена поддержка rename.
>>> # 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() -
Возвращает новый
OrderedDict, который сопоставляет имена полей с соответствующими значениями:>>> p = Point(x=11, y=22) >>> p._asdict() OrderedDict([('x', 11), ('y', 22)])Изменено в версии 3.1: Возвращает
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._source -
Строка с исходным кодом на чистом Python, используемым для создания класса именованного кортежа. Исходный код делает именованный кортеж самодокументирующим. Его можно напечатать, выполнить с помощью
exec()или сохранить в файл и импортировать.Добавлена в версии 3.3.
-
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',))
Документационные строки можно настроить, выполнив прямые присваивания полям __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: Документационные строки свойств стали изменяемыми.
Значения по умолчанию можно реализовать, используя _replace() для настройки экземпляра-прототипа:
>>> Account = namedtuple('Account', 'owner balance transaction_count')
>>> default_account = Account('<owner name>', 0.0, 0)
>>> johns_account = default_account._replace(owner='John')
>>> janes_account = default_account._replace(owner='Jane')
См. также
- Рецепт именованного кортежа абстрактного базового класса с примесью метакласса Яном Калишевским. Помимо предоставления абстрактного базового класса для именованных кортежей, он также поддерживает альтернативный метакласс-основанный конструктор, удобный для случаев, когда именованные кортежи являются подклассами.
6. Объекты OrderedDict
Обычные словари, но они запоминают порядок вставки элементов. При итерации по упорядоченному словарю элементы возвращаются в порядке, в котором были добавлены их ключи.
-
class collections.OrderedDict([items]) -
Возвращает экземпляр подкласса dict, поддерживающего обычные методы
dict. OrderedDict — это словарь, который запоминает порядок вставки ключей. Если новая запись перезаписывает существующую запись, исходная позиция вставки остаётся неизменной. Удаление записи и её повторная вставка переместят её в конец.Новое в версии 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 везде, где используется обычный словарь.
Конструктор OrderedDict и метод update() оба принимают ключевые аргументы, но их порядок теряется, потому что семантика вызова функций Python передает ключевые аргументы с помощью обычного неупорядоченного словаря.
Изменено в версии 3.5: Просмотры элементов, ключей и значений отображений OrderedDict теперь поддерживают обратную итерацию с помощью reversed().
6.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),)
7. Объекты UserDict
Класс UserDict действует как оболочка вокруг объектов словарей. Необходимость в этом классе частично заменена возможностью прямого наследования от dict; однако, этот класс может быть проще в использовании, потому что базовый словарь доступен как атрибут.
-
class collections.UserDict([initialdata]) -
Класс, имитирующий словарь. Содержимое экземпляра хранится в обычном словаре, доступном через атрибут
dataэкземпляровUserDict. Если указан initialdata,dataинициализируется его содержимым; обратите внимание, что ссылка на initialdata не сохраняется, что позволяет использовать его для других целей.Помимо поддержки методов и операций отображений, экземпляры
UserDictпредоставляют следующий атрибут:-
data -
Реальный словарь, используемый для хранения содержимого класса
UserDict.
-
8. Объекты UserList
Этот класс действует как оболочка вокруг списков. Он является полезным базовым классом для собственных спископодобных классов, которые могут наследоваться от него и переопределять существующие методы или добавлять новые. Таким образом, можно добавлять новые функции к спискам.
Необходимость в этом классе частично заменена возможностью прямого наследования от list; однако, этот класс может быть проще в использовании, потому что базовый список доступен как атрибут.
-
class collections.UserList([list]) -
Класс, имитирующий список. Содержимое экземпляра хранится в обычном списке, доступном через атрибут
dataэкземпляровUserList. Содержимое экземпляра изначально устанавливается в копию list, по умолчанию — пустой список[]. list может быть любым итерируемым объектом, например, реальным списком Python или объектомUserList.Помимо поддержки методов и операций изменяемых последовательностей, экземпляры
UserListпредоставляют следующий атрибут:
Требования к подклассам: От подклассов UserList ожидается, что они предложат конструктор, который можно вызвать либо без аргументов, либо с одним аргументом. Операции со списками, возвращающие новую последовательность, пытаются создать экземпляр фактического класса реализации. Для этого предполагается, что конструктор может быть вызван с одним параметром, который является объектом последовательности, используемым в качестве источника данных.
Если производный класс не хочет соответствовать этому требованию, все специальные методы, поддерживаемые этим классом, необходимо будет переопределить; обратитесь к исходным данным за информацией о методах, которые необходимо предоставить в этом случае.
9. Объекты UserString
Класс UserString действует как обёртка вокруг строковых объектов. Необходимость в этом классе частично заменена возможностью непосредственного наследования от str; однако, с этим классом работать может быть проще, так как основная строка доступна как атрибут.
-
class collections.UserString([sequence]) -
Класс, имитирующий строковый или строковый Unicode объект. Содержимое экземпляра хранится в обычном строковом объекте, доступном через атрибут
dataэкземпляровUserString. Содержимое экземпляра изначально устанавливается в копию sequence. sequence может быть экземпляромbytes,str,UserString(или подкласса) или произвольной последовательностью, которая может быть преобразована в строку с помощью встроенной функцииstr().Изменено в версии 3.5: Новые методы
__getnewargs__,__rmod__,casefold,format_map,isprintable, иmaketrans.
© 2001–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.5/library/collections.html