collections — Типы контейнерных данных
Исходный код: Lib/collections/__init__.py
В этом модуле реализованы специализированные контейнерные типы данных, предлагающие альтернативу встроенным контейнерам общего назначения Python, dict, list, set и tuple.
функция-фабрика для создания подклассов кортежей с именованными полями | |
подобный списку контейнер с быстрыми добавлениями и удалениями элементов в начале и конце | |
класс, подобный словарю, для создания единого представления нескольких отображений | |
подкласс словаря для подсчета хэшируемых объектов | |
подкласс словаря, запоминающий порядок добавления элементов | |
подкласс словаря, вызывающий функцию-фабрику для предоставления пропущенных значений | |
обертка вокруг объектов словаря для более простого наследования от словаря | |
обертка вокруг списков для более простого наследования от списка | |
обертка вокруг строковых объектов для более простого наследования от строки |
Устаревшее с версии 3.3, будет удалено в версии 3.9: Перемещено Абстрактные базовые классы коллекций в модуль collections.abc. Для обратной совместимости они по-прежнему доступны в этом модуле до Python 3.8.
Объекты ChainMap
Введено в версии 3.3.
Класс ChainMap предназначен для быстрого связывания нескольких отображений, чтобы их можно было рассматривать как единое целое. Часто он значительно быстрее, чем создание нового словаря и выполнение нескольких вызовов update().
Класс можно использовать для моделирования вложенных областей видимости и он полезен в шаблонах.
-
class collections.ChainMap(*maps) -
Класс
ChainMapобъединяет несколько словарей или других отображений, чтобы создать единое обновляемое представление. Если отображения не указаны, предоставляется один пустой словарь, чтобы новая цепочка всегда содержала по крайней мере одно отображение.Базовые отображения хранятся в списке. Этот список общедоступен и может быть изменен с помощью атрибута отображения. Другого состояния нет.
Обращения к ключам ищут их последовательно в базовых отображениях до тех пор, пока ключ не будет найден. В отличие от этого, записи, обновления и удаления выполняются только для первого отображения.
Класс
ChainMapиспользует ссылки на базовые отображения. Таким образом, если одно из базовых отображений обновляется, эти изменения будут отражены вChainMap.Поддерживаются все обычные методы словарей. Кроме того, есть атрибут отображения, метод для создания новых подконтекстов и свойство для доступа ко всем отображениям, кроме первого:
-
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']
-
См. также
- Класс MultiContext в пакете Enthought CodeTools имеет возможности для записи в любое отображение в цепочке.
- Класс Context Django для шаблонов — это только для чтения цепочка отображений. Он также предоставляет функции добавления и удаления контекстов, аналогичные методу
new_child()и свойствуparents. - Рецепт «Вложенные контексты» предоставляет возможности управления тем, относятся ли записи и другие изменения только к первому отображению или ко всем отображениям в цепочке.
- Упрощенная версия 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'})
Объекты 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 a 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) [('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])
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++ многомножества учебник с примерами.
- Для математических операций над мультисетами и их приложений см. 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 objects
-
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.
-
В дополнение к вышеперечисленному, deque поддерживает итерацию, сериализацию, len(d), reversed(d), copy.copy(d), copy.deepcopy(d), проверку на принадлежность с помощью оператора in и ссылок на подстроки, такие как d[-1]. Индексированный доступ — O(1) на обоих концах, но замедляется до O(n) посередине. Для быстрого случайного доступа используйте списки.
Начиная с версии 3.5, deque поддерживает __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 Рецепты
Этот раздел показывает различные подходы к работе с deque.
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)
Другой подход к использованию 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 / 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 реализация срезов deque опирается на метод 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[, ...]]) -
Возвращает новый объект, похожий на словарь.
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, если его нет.
-
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. Новый подкласс используется для создания объектов, похожих на кортежи, которые имеют поля, доступные по имени поля, а также индексируемы и итерируемы. Экземпляры подкласса также имеют полезную строку документации (с именем типа и именами полей) и полезный метод
__repr__(), который отображает содержимое кортежа вname=valueформате.field_names — это последовательность строк, например,
['x', 'y']. В качестве альтернативы field_names может быть одной строкой, где каждое имя поля отделяется пробелами и/или запятыми, например,'x y'или'x, y'.Любое допустимое имя Python может использоваться в качестве имени поля, за исключением имён, начинающихся с нижнего подчёркивания. Допустимые идентификаторы состоят из букв, цифр и подчёркиваний, но не начинаются с цифры или подчёркивания и не могут быть
keyword, такими как class, for, return, global, pass или raise.Если rename равно true, недопустимые имена полей автоматически заменяются позиционными именами. Например,
['abc', 'def', 'ghi', 'abc']преобразуется в['abc', '_1', 'ghi', '_3'], исключая ключевое словоdefи дублирующее имя поляabc.defaults может быть
Noneили итерируемым значением по умолчанию. Поскольку поля со значением по умолчанию должны следовать за полями без значения по умолчанию, значения по умолчанию применяются к правым параметрам. Например, если имена полей —['x', 'y', 'z']и значения по умолчанию —(1, 2), тоxбудет обязательным аргументом,yбудет иметь значение по умолчанию1, аzбудет иметь значение по умолчанию2.Если module определено, атрибут
__module__именованного кортежа устанавливается в это значение.Экземпляры именованных кортежей не имеют словарей на уровне экземпляра, поэтому они лёгкие и требуют не больше памяти, чем обычные кортежи.
Изменено в версии 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() 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._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: Документация по свойствам стала изменяемой.
Значения по умолчанию можно реализовать, используя _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')
См. также
-
См.
typing.NamedTuple, чтобы добавить подсказки типов для кортежей с именами полей. Он также предоставляет элегантную запись, использующую ключевое словоclass:class Component(NamedTuple): part_number: int weight: float description: Optional[str] = None - См.
types.SimpleNamespace()для изменяемого пространства имён, основанного на базовом словаре, а не на кортеже. - Модуль
dataclassesпредоставляет декоратор и функции для автоматического добавления сгенерированных специальных методов в пользовательские классы.
Объекты OrderedDict
Словари 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()для словарей OrderedDict возвращает и удаляет пару (ключ, значение). Пары возвращаются в порядке LIFO, если last имеет значение true, или в порядке FIFO, если оно имеет значение false.
-
move_to_end(key, last=True) -
Перемещает существующий ключ в конец или начало словаря OrderedDict. Элемент перемещается в конец, если last имеет значение true (по умолчанию), или в начало, если last имеет значение false. Вызывает
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.
-
В дополнение к обычным методам отображения, словари OrderedDict также поддерживают обратную итерацию с помощью reversed().
Тесты на равенство между объектами OrderedDict чувствительны к порядку и реализуются как list(od1.items())==list(od2.items()). Тесты на равенство между объектами OrderedDict и другими объектами Mapping нечувствительны к порядку, как и обычные словари. Это позволяет использовать объекты OrderedDict в любом месте, где используется обычный словарь.
Изменено в версии 3.5: Просмотры элементов, ключей и значений views OrderedDict теперь поддерживают обратную итерацию с помощью reversed().
Изменено в версии 3.6: После принятия PEP 468 порядок сохраняется для ключевых аргументов, переданных в конструктор OrderedDict, и его метода update().
OrderedDict Примеры и рецепты
Легко создать вариант словаря OrderedDict, который запоминает порядок последних вставок ключей. Если новая запись перезаписывает существующую запись, исходная позиция вставки изменяется и перемещается в конец:
class LastUpdatedOrderedDict(OrderedDict):
'Store items in the order the keys were last added'
def __setitem__(self, key, value):
super().__setitem__(key, value)
super().move_to_end(key)
Класс OrderedDict также будет полезен для реализации вариантов functools.lru_cache():
class LRU(OrderedDict):
'Limit size, evicting the least recently looked-up key when full'
def __init__(self, maxsize=128, *args, **kwds):
self.maxsize = maxsize
super().__init__(*args, **kwds)
def __getitem__(self, key):
value = super().__getitem__(key)
self.move_to_end(key)
return value
def __setitem__(self, key, value):
super().__setitem__(key, value)
if len(self) > self.maxsize:
oldest = next(iter(self))
del self[oldest]
Объекты 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предоставляют следующий атрибут:
Требования к наследованию: Подклассы 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–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.7/library/collections.html