collections — Высокопроизводительные контейнерные типы данных
Новое в версии 2.4.
Исходный код: Lib/collections.py и Lib/_abcoll.py
Этот модуль реализует специализированные контейнерные типы данных, предоставляющие альтернативы встроенным контейнерам Python общего назначения, dict, list, set и tuple.
функция-фабрика для создания подклассов кортежей с именованными полями |
Новое в версии 2.6. | |
подобный списку контейнер с быстрыми добавлениями и удалениями в начале и в конце |
Новое в версии 2.4. | |
подкласс словаря для подсчета хэшируемых объектов |
Новое в версии 2.7. | |
подкласс словаря, запоминающий порядок добавления элементов |
Новое в версии 2.7. | |
подкласс словаря, вызывающий функцию-фабрику для предоставления пропущенных значений |
Новое в версии 2.5. |
Помимо конкретных классов контейнеров, модуль collections предоставляет абстрактные базовые классы, которые могут использоваться для проверки, предоставляет ли класс определенный интерфейс, например, является ли он хэшируемым или отображением.
1. Объекты Counter
Для удобного и быстрого подсчета предоставляется инструмент Counter. Например:
>>> # Tally occurrences of words in a list
>>> cnt = Counter()
>>> for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
... cnt[word] += 1
>>> cnt
Counter({'blue': 3, 'red': 2, 'green': 1})
>>> # Find the ten most common words in Hamlet
>>> import re
>>> words = re.findall(r'\w+', open('hamlet.txt').read().lower())
>>> Counter(words).most_common(10)
[('the', 1143), ('and', 966), ('to', 762), ('of', 669), ('i', 631),
('you', 554), ('a', 546), ('my', 514), ('hamlet', 471), ('in', 451)]
-
class collections.Counter([iterable-or-mapping]) -
Counter— это подклассdictдля подсчета хэшируемых объектов. Это неупорядоченное множество, где элементы хранятся в качестве ключей словаря, а их количество — в качестве значений словаря. Количество может быть любым целым числом, включая ноль или отрицательные значения.Элементы подсчитываются из итерируемого объекта или инициализируются из другого отображения (или счётчика):
>>> c = Counter() # a new, empty counter >>> c = Counter('gallahad') # a new counter from an iterable >>> c = Counter({'red': 4, 'blue': 2}) # a new counter from a mapping >>> c = Counter(cats=4, dogs=8) # a new counter from keyword argsОбъекты Counter имеют интерфейс словаря, за исключением того, что они возвращают нулевой счёт для отсутствующих элементов вместо повышения
KeyError:>>> c = Counter(['eggs', 'ham']) >>> c['bacon'] # count of a missing element is zero 0
Установить счёт в ноль не удаляет элемент из счётчика. Используйте
delдля его полного удаления:>>> c['sausage'] = 0 # counter entry with a zero count >>> del c['sausage'] # del actually removes the entry
Новое в версии 2.7.
Объекты Counter поддерживают три метода помимо тех, которые доступны для всех словарей:
-
elements() -
Возвращает итератор по элементам, повторяя каждый элемент столько раз, сколько указано в его счётчике. Элементы возвращаются в произвольном порядке. Если счёт элемента меньше единицы,
elements()его игнорирует.>>> c = Counter(a=4, b=2, c=0, d=-2) >>> list(c.elements()) ['a', 'a', 'a', 'a', 'b', 'b']
-
most_common([n]) -
Возвращает список n наиболее часто встречающихся элементов и их счётчиков, от наиболее часто встречающегося к наименее часто встречающемуся. Если n опущен или
None,most_common()возвращает все элементы счётчика. Элементы с одинаковыми счётчиками упорядочиваются произвольно:>>> Counter('abracadabra').most_common(3) [('a', 5), ('r', 2), ('b', 2)]
-
subtract([iterable-or-mapping]) -
Элементы вычитаются из итерируемого объекта или из другого отображения (или счётчика). Подобно
dict.update(), но вычитает счётчики вместо их замены. Входные и выходные значения могут быть нулевыми или отрицательными.>>> c = Counter(a=4, b=2, c=0, d=-2) >>> d = Counter(a=1, b=2, c=3, d=4) >>> c.subtract(d) >>> c Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})
Обычные методы словаря доступны для объектов
Counter, за исключением двух, которые работают по-другому для счётчиков.-
fromkeys(iterable) -
Этот метод класса не реализован для объектов
Counter.
-
update([iterable-or-mapping]) -
Элементы подсчитываются из итерируемого объекта или добавляются из другого отображения (или счётчика). Подобно
dict.update(), но добавляет счётчики вместо их замены. Кроме того, ожидается, что итерируемый объект будет последовательностью элементов, а не последовательностью пар(key, value).
-
Общие паттерны работы с объектами Counter:
sum(c.values()) # total of all counts c.clear() # reset all counts list(c) # list unique elements set(c) # convert to a set dict(c) # convert to a regular dictionary c.items() # convert to a list of (elem, cnt) pairs Counter(dict(list_of_pairs)) # convert from a list of (elem, cnt) pairs c.most_common()[:-n-1:-1] # n least common elements c += Counter() # remove zero and negative counts
Несколько математических операций предоставляются для объединения объектов Counter для создания мультимножеств (счётчиков, у которых количество элементов больше нуля). Сложение и вычитание объединяют счётчики, добавляя или вычитая соответствующие количества элементов. Пересечение и объединение возвращают минимальное и максимальное количество соответствующих счётчиков. Каждая операция может принимать входные данные с положительными, нулевыми и отрицательными счётчиками, но выход будет исключать результаты с нулевыми или отрицательными счётчиками.
>>> c = Counter(a=3, b=1)
>>> d = Counter(a=1, b=2)
>>> c + d # add two counters together: c[x] + d[x]
Counter({'a': 4, 'b': 3})
>>> c - d # subtract (keeping only positive counts)
Counter({'a': 2})
>>> c & d # intersection: min(c[x], d[x])
Counter({'a': 1, 'b': 1})
>>> c | d # union: max(c[x], d[x])
Counter({'a': 3, 'b': 2})
Примечание
Счётчики были разработаны в первую очередь для работы с положительными целыми числами для представления текущих подсчётов; однако, были приняты меры для того, чтобы не исключать излишне случаи использования других типов или отрицательных значений. Для поддержки таких случаев этот раздел документирует минимальные ограничения по диапазону и типу.
- Класс
Counterсам по себе является подклассом словаря без ограничений на его ключи и значения. Значения предназначены для представления количества, но вы можете хранить в поле значения что угодно. - Метод
most_common()требует только, чтобы значения были упорядочиваемы. - Для операций на месте, таких как
c[key] += 1, тип значения должен поддерживать сложение и вычитание. Так что дроби, числа с плавающей точкой и десятичные числа будут работать, и поддерживаются отрицательные значения. То же самое относится кupdate()иsubtract(), которые допускают отрицательные и нулевые значения для входных и выходных данных. - Методы мультимножеств разработаны только для случаев использования с положительными значениями. Входные данные могут быть отрицательными или нулевыми, но создаются только выходные данные с положительными значениями. Ограничений на тип нет, но тип значения должен поддерживать сложение, вычитание и сравнение.
- Метод
elements()требует целочисленных счётчиков. Он игнорирует нулевые и отрицательные счётчики.
См. также
- Класс Counter адаптирован для Python 2.5 и ранний рецепт Bag для Python 2.4.
- Класс Bag в Smalltalk.
- Статья в Википедии о Мультимножествах.
- C++ мультимножества учебное пособие с примерами.
- Для математических операций над мультимножествами и их случаев использования см. Knuth, Donald. Искусство программирования ЭВМ, том II, раздел 4.6.3, упражнение 19.
-
Для перечисления всех различных мультимножеств заданного размера над заданным набором элементов см.
itertools.combinations_with_replacement().map(Counter, combinations_with_replacement(‘ABC’, 2)) –> AA AB AC BB BC CC
2. Объекты deque
-
class collections.deque([iterable[, maxlen]]) -
Возвращает новый объект deque, инициализированный слева направо (используя
append()) данными из iterable. Если iterable не указан, новый deque пустой.Deque — это обобщение стеков и очередей (название произносится как «дек» и сокращение от «двусторонней очереди»). Deque поддерживает потокобезопасные, эффективные с точки зрения памяти добавления и удаления элементов с обеих сторон deque с примерно одинаковой производительностью O(1) в любом направлении.
Хотя
listобъекты поддерживают аналогичные операции, они оптимизированы для быстрых операций с фиксированной длиной и несут затраты O(n) на перемещение памяти для операцийpop(0)иinsert(0, v), которые изменяют и размер, и положение базового представления данных.Введено в версии 2.4.
Если maxlen не указан или равен
None, deque может расти до произвольной длины. В противном случае, deque ограничен указанной максимальной длиной. После того, как deque с ограниченной длиной заполнится, при добавлении новых элементов соответствующее количество элементов удаляется с противоположного конца. Deque с ограниченной длиной обеспечивает функциональность, аналогичную фильтруtailв Unix. Они также полезны для отслеживания транзакций и других наборов данных, где важна только самая последняя активность.Изменено в версии 2.6: Добавлен параметр maxlen.
Объекты deque поддерживают следующие методы:
-
append(x) -
Добавить x в правую сторону deque.
-
appendleft(x) -
Добавить x в левую сторону deque.
-
clear() -
Удалить все элементы из deque, оставив его длиной 0.
-
count(x) -
Подсчитать количество элементов deque, равных x.
Введено в версии 2.7.
-
extend(iterable) -
Расширить правую сторону deque, добавив элементы из итерируемого аргумента.
-
extendleft(iterable) -
Расширить левую сторону deque, добавив элементы из iterable. Обратите внимание, последовательность добавлений слева приводит к изменению порядка элементов в аргументе iterable.
-
pop() -
Удалить и вернуть элемент с правой стороны deque. Если элементов нет, возникает
IndexError.
-
popleft() -
Удалить и вернуть элемент с левой стороны deque. Если элементов нет, возникает
IndexError.
-
remove(value) -
Удалить первое вхождение value. Если не найдено, возникает
ValueError.Введено в версии 2.5.
-
reverse() -
Инвертировать элементы deque на месте и вернуть
None.Введено в версии 2.7.
-
rotate(n=1) -
Повернуть deque на n шагов вправо. Если n отрицательное, повернуть влево.
Когда deque не пуст, поворот на один шаг вправо эквивалентен
d.appendleft(d.pop()), а поворот на один шаг влево эквивалентенd.append(d.popleft()).
Объекты deque также предоставляют один только для чтения атрибут:
-
maxlen -
Максимальный размер deque или
None, если безграничен.Введено в версии 2.7.
-
Помимо вышеперечисленного, deque поддерживает итерацию, сериализацию, len(d), reversed(d), copy.copy(d), copy.deepcopy(d), проверку членства с помощью оператора in и индексированные ссылки, такие как d[-1]. Индексированный доступ имеет сложность O(1) на обоих концах, но замедляется до O(n) посередине. Для быстрого случайного доступа используйте списки.
Пример:
>>> from collections import deque
>>> d = deque('ghi') # make a new deque with three items
>>> for elem in d: # iterate over the deque's elements
... print elem.upper()
G
H
I
>>> d.append('j') # add a new entry to the right side
>>> d.appendleft('f') # add a new entry to the left side
>>> d # show the representation of the deque
deque(['f', 'g', 'h', 'i', 'j'])
>>> d.pop() # return and remove the rightmost item
'j'
>>> d.popleft() # return and remove the leftmost item
'f'
>>> list(d) # list the contents of the deque
['g', 'h', 'i']
>>> d[0] # peek at leftmost item
'g'
>>> d[-1] # peek at rightmost item
'i'
>>> list(reversed(d)) # list the contents of a deque in reverse
['i', 'h', 'g']
>>> 'h' in d # search the deque
True
>>> d.extend('jkl') # add multiple elements at once
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> d.rotate(1) # right rotation
>>> d
deque(['l', 'g', 'h', 'i', 'j', 'k'])
>>> d.rotate(-1) # left rotation
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> deque(reversed(d)) # make a new deque in reverse order
deque(['l', 'k', 'j', 'i', 'h', 'g'])
>>> d.clear() # empty the deque
>>> d.pop() # cannot pop from an empty deque
Traceback (most recent call last):
File "<pyshell#6>", line 1, in -toplevel-
d.pop()
IndexError: pop from an empty deque
>>> d.extendleft('abc') # extendleft() reverses the input order
>>> d
deque(['c', 'b', 'a'])
2.1. deque Рецепты
Этот раздел показывает различные подходы к работе с deque.
Deques с ограниченной длиной обеспечивают функциональность, аналогичную фильтру tail в Unix:
def tail(filename, n=10):
'Return the last n lines of a file'
return deque(open(filename), n)
Другой подход к использованию deque — это поддержание последовательности недавно добавленных элементов, добавляя вправо и удаляя слева:
def moving_average(iterable, n=3):
# moving_average([40, 30, 50, 46, 39, 44]) --> 40.0 42.0 45.0 43.0
# http://en.wikipedia.org/wiki/Moving_average
it = iter(iterable)
d = deque(itertools.islice(it, n-1))
d.appendleft(0)
s = sum(d)
for elem in it:
s += elem - d.popleft()
d.append(elem)
yield s / float(n)
Метод rotate() предоставляет способ реализации deque срезов и удаления. Например, чистое имплементация Python del d[n] опирается на метод rotate() для позиционирования элементов, которые нужно удалить:
def delete_nth(d, n):
d.rotate(-n)
d.popleft()
d.rotate(n)
Для реализации deque срезов используйте аналогичный подход, применяя rotate() для перемещения целевого элемента в левую сторону deque. Удаляйте старые записи с помощью popleft(), добавляйте новые записи с помощью extend(), а затем инвертируйте поворот. С небольшими вариациями этого подхода легко реализовать манипуляции со стеком в стиле Forth, такие как dup, drop, swap, over, pick, rot, и roll.
3. Объекты defaultdict
-
class collections.defaultdict([default_factory[, ...]]) -
Возвращает новый похожий на словарь объект.
defaultdictявляется подклассом встроенного классаdict. Он переопределяет один метод и добавляет одну изменяемую переменную экземпляра. Остальная функциональность такая же, как у классаdictи здесь не документируется.Первый аргумент предоставляет начальное значение для атрибута
default_factory; по умолчанию он равенNone. Все остальные аргументы обрабатываются так же, как если бы они были переданы конструкторуdict, включая ключевые аргументы.Введено в версии 2.5.
Объекты
defaultdictподдерживают следующий метод в дополнение к стандартным операциямdict:-
__missing__(key) -
Если атрибут
default_factoryравенNone, это вызывает исключениеKeyErrorс key в качестве аргумента.Если
default_factoryне равноNone, он вызывается без аргументов, чтобы предоставить значение по умолчанию для данного key, это значение вставляется в словарь для key и возвращается.Если вызов
default_factoryвызывает исключение, это исключение распространяется без изменений.Этот метод вызывается методом
__getitem__()классаdict, когда запрашиваемый ключ не найден; всё, что он возвращает или вызывает, возвращается или вызывается методом__getitem__().Обратите внимание, что
__missing__()не вызывается для каких-либо операций, кроме__getitem__(). Это означает, чтоget()будет, как и обычные словари, возвращатьNoneв качестве значения по умолчанию, а не использоватьdefault_factory.
Объекты
defaultdictподдерживают следующую переменную экземпляра:-
default_factory -
Этот атрибут используется методом
__missing__(); он инициализируется из первого аргумента конструктора, если он есть, или равенNone, если отсутствует.
-
3.1. defaultdict Примеры
Используя list в качестве default_factory, легко сгруппировать последовательность пар «ключ-значение» в словарь списков:
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
... d[k].append(v)
...
>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
Когда ключ встречается впервые, его ещё нет в отображении; поэтому запись автоматически создаётся с помощью функции default_factory, возвращающей пустой list. Затем операция list.append() присоединяет значение к новому списку. Когда ключи встречаются снова, поиск происходит нормально (возвращая список для данного ключа), и операция list.append() добавляет ещё одно значение в список. Этот метод проще и быстрее, чем аналогичный метод с использованием dict.setdefault():
>>> d = {}
>>> for k, v in s:
... d.setdefault(k, []).append(v)
...
>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
Установка default_factory в int делает defaultdict полезным для подсчёта (как мешок или мультимножество в других языках):
>>> s = 'mississippi'
>>> d = defaultdict(int)
>>> for k in s:
... d[k] += 1
...
>>> d.items()
[('i', 4), ('p', 2), ('s', 4), ('m', 1)]
Когда буква встречается впервые, её нет в отображении, поэтому функция default_factory вызывает int() для задания значения по умолчанию — нуля. Затем операция инкремента наращивает счётчик для каждой буквы.
Функция int(), которая всегда возвращает ноль, — это всего лишь частный случай постоянных функций. Более быстрый и гибкий способ создания постоянных функций — использование itertools.repeat(), которое может обеспечить любое постоянное значение (не только ноль):
>>> def constant_factory(value):
... return itertools.repeat(value).next
>>> d = defaultdict(constant_factory('<missing>'))
>>> d.update(name='John', action='ran')
>>> '%(name)s %(action)s to %(object)s' % d
'John ran to <missing>'
Установка default_factory в set делает defaultdict полезным для построения словаря множеств:
>>> s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
>>> d = defaultdict(set)
>>> for k, v in s:
... d[k].add(v)
...
>>> d.items()
[('blue', set([2, 4])), ('red', set([1, 3]))]
4. namedtuple() Функция-фабрика для кортежей с именованными полями
Именованные кортежи присваивают смысл каждой позиции в кортеже и позволяют создавать более читаемый и самодокументированный код. Их можно использовать везде, где используются обычные кортежи, и они добавляют возможность доступа к полям по имени вместо индекса позиции.
-
collections.namedtuple(typename, field_names[, verbose=False][, rename=False]) -
Возвращает новый подкласс кортежа с именем typename. Новый подкласс используется для создания объектов, похожих на кортежи, которые имеют поля, доступные по имени атрибута, а также индексируемые и итерируемые. Экземпляры подкласса также имеют полезную строку документации (с именем типа и именами полей) и полезный метод
__repr__(), который выводит содержимое кортежа в форматеname=value.field_names — это последовательность строк, например,
['x', 'y']. В качестве альтернативы field_names может быть одной строкой, где каждое имя поля разделено пробелом и/или запятыми, например,'x y'или'x, y'.Любое допустимое имя Python может использоваться для имени поля, за исключением имён, начинающихся с нижнего подчёркивания. Допустимые идентификаторы состоят из букв, цифр и подчёркиваний, но не начинаются с цифры или подчёркивания и не могут быть
keyword, такими как class, for, return, global, pass, print или raise.Если rename равно true, недопустимые имена полей автоматически заменяются позиционными именами. Например,
['abc', 'def', 'ghi', 'abc']преобразуется в['abc', '_1', 'ghi', '_3'], исключая ключевое словоdefи дублируемое имя поляabc.Если verbose равно true, определение класса выводится перед созданием.
Экземпляры именованных кортежей не имеют словарей на экземпляр, поэтому они легкие и не требуют больше памяти, чем обычные кортежи.
Добавлена в версии 2.6.
Изменено в версии 2.7: добавлена поддержка rename.
Пример:
>>> Point = namedtuple('Point', ['x', 'y'], verbose=True)
class Point(tuple):
'Point(x, y)'
__slots__ = ()
_fields = ('x', 'y')
def __new__(_cls, x, y):
'Create new instance of Point(x, y)'
return _tuple.__new__(_cls, (x, y))
@classmethod
def _make(cls, iterable, new=tuple.__new__, len=len):
'Make a new Point object from a sequence or iterable'
result = new(cls, iterable)
if len(result) != 2:
raise TypeError('Expected 2 arguments, got %d' % len(result))
return result
def __repr__(self):
'Return a nicely formatted representation string'
return 'Point(x=%r, y=%r)' % self
def _asdict(self):
'Return a new OrderedDict which maps field names to their values'
return OrderedDict(zip(self._fields, self))
def _replace(_self, **kwds):
'Return a new Point object replacing specified fields with new values'
result = _self._make(map(kwds.pop, ('x', 'y'), _self))
if kwds:
raise ValueError('Got unexpected field names: %r' % kwds.keys())
return result
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return tuple(self)
__dict__ = _property(_asdict)
def __getstate__(self):
'Exclude the OrderedDict from pickling'
pass
x = _property(_itemgetter(0), doc='Alias for field number 0')
y = _property(_itemgetter(1), doc='Alias for field number 1')
>>> p = Point(11, y=22) # instantiate with positional or keyword arguments
>>> p[0] + p[1] # indexable like the plain tuple (11, 22)
33
>>> x, y = p # unpack like a regular tuple
>>> x, y
(11, 22)
>>> p.x + p.y # fields also accessible by name
33
>>> p # readable __repr__ with a name=value style
Point(x=11, y=22)
Именованные кортежи особенно полезны для присвоения имён полей кортежам результатов, возвращаемым модулями csv или sqlite3:
EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')
import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))):
print emp.name, emp.title
import sqlite3
conn = sqlite3.connect('/companydata')
cursor = conn.cursor()
cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
for emp in map(EmployeeRecord._make, cursor.fetchall()):
print emp.name, emp.title
В дополнение к методам, унаследованным от кортежей, именованные кортежи поддерживают три дополнительных метода и один атрибут. Чтобы избежать конфликтов с именами полей, имена методов и атрибутов начинаются с подчёркивания.
-
classmethod somenamedtuple._make(iterable) -
Метод класса, создающий новый экземпляр из существующей последовательности или итерируемого объекта.
>>> t = [11, 22] >>> Point._make(t) Point(x=11, y=22)
-
somenamedtuple._asdict() -
Возвращает новый словарь
OrderedDict, сопоставляющий имена полей с соответствующими значениями:>>> p = Point(x=11, y=22) >>> p._asdict() OrderedDict([('x', 11), ('y', 22)])Изменено в версии 2.7: Возвращает
OrderedDictвместо обычногоdict.
-
somenamedtuple._replace(**kwargs) -
Возвращает новый экземпляр именованного кортежа, заменяя указанные поля новыми значениями:
>>> p = Point(x=11, y=22) >>> p._replace(x=33) Point(x=33, y=22) >>> for partnum, record in inventory.items(): ... inventory[partnum] = record._replace(price=newprices[partnum], timestamp=time.now())
-
somenamedtuple._fields -
Кортеж строк, перечисляющий имена полей. Полезен для интроспекции и для создания новых типов именованных кортежей из существующих.
>>> p._fields # view the field names ('x', 'y') >>> Color = namedtuple('Color', 'red green blue') >>> Pixel = namedtuple('Pixel', Point._fields + Color._fields) >>> Pixel(11, 22, 128, 255, 0) Pixel(x=11, y=22, red=128, green=255, blue=0)
Чтобы получить поле, имя которого хранится в строке, используйте функцию getattr():
>>> getattr(p, 'x') 11
Чтобы преобразовать словарь в именованный кортеж, используйте оператор двойной звёздочки (как описано в Развёртывание списков аргументов):
>>> d = {'x': 11, 'y': 22}
>>> Point(**d)
Point(x=11, y=22)
Поскольку именованный кортеж — это обычный класс Python, его функциональность легко добавить или изменить с помощью подкласса. Вот как добавить вычисляемое поле и формат вывода с фиксированной шириной:
>>> class Point(namedtuple('Point', 'x y')):
... __slots__ = ()
... @property
... def hypot(self):
... return (self.x ** 2 + self.y ** 2) ** 0.5
... def __str__(self):
... return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, self.hypot)
...
>>> for p in Point(3, 4), Point(14, 5/7.):
... print p
Point: x= 3.000 y= 4.000 hypot= 5.000
Point: x=14.000 y= 0.714 hypot=14.018
В показанном выше подклассе __slots__ устанавливается в пустой кортеж. Это помогает поддерживать низкие требования к памяти, предотвращая создание словарей экземпляров.
Наследование не подходит для добавления новых, хранящихся полей. Вместо этого просто создайте новый тип именованного кортежа из атрибута _fields:
>>> Point3D = namedtuple('Point3D', Point._fields + ('z',))
Значения по умолчанию можно реализовать с помощью _replace() для настройки экземпляра-прототипа:
>>> Account = namedtuple('Account', 'owner balance transaction_count')
>>> default_account = Account('<owner name>', 0.0, 0)
>>> johns_account = default_account._replace(owner='John')
Перечислимые константы можно реализовать с помощью именованных кортежей, но проще и эффективнее использовать простое объявление класса:
>>> Status = namedtuple('Status', 'open pending closed')._make(range(3))
>>> Status.open, Status.pending, Status.closed
(0, 1, 2)
>>> class Status:
... open, pending, closed = range(3)
См. также
Рецепт именованного кортежа адаптирован для Python 2.4.
5. OrderedDict объекты
Словари OrderedDict такие же, как и обычные словари, но они запоминают порядок добавления элементов. При итерации по словарям OrderedDict элементы возвращаются в порядке, в котором ключи были добавлены впервые.
-
class collections.OrderedDict([items]) -
Возвращает экземпляр подкласса словаря, поддерживающий обычные методы
dict. OrderedDict — это словарь, который запоминает порядок добавления ключей. Если новая запись перезаписывает существующую, исходная позиция вставки остаётся неизменной. Удаление записи и повторная вставка перемещает её в конец.Добавлена в версии 2.7.
-
OrderedDict.popitem(last=True) -
Метод
popitem()для словарей OrderedDict возвращает и удаляет пару «ключ-значение». Пары возвращаются в порядке LIFO, если last равно true, или в порядке FIFO, если false.
В дополнение к обычным методам отображения, словари OrderedDict также поддерживают обратную итерацию с использованием reversed().
Тесты на равенство между объектами OrderedDict чувствительны к порядку и реализуются как list(od1.items())==list(od2.items()). Тесты на равенство между объектами OrderedDict и другими объектами Mapping нечувствительны к порядку, как и обычные словари. Это позволяет использовать объекты OrderedDict везде, где используются обычные словари.
Конструктор OrderedDict и метод update() оба принимают именованные аргументы, но их порядок теряется, поскольку семантика вызова функций Python передаёт именованные аргументы с использованием обычного неупорядоченного словаря.
См. также
Эквивалентный рецепт OrderedDict, который работает на Python 2.4 или более поздних версиях.
5.1. OrderedDict Примеры и рецепты
Поскольку упорядоченный словарь запоминает порядок вставки, его можно использовать совместно с сортировкой для создания отсортированного словаря:
>>> # regular unsorted dictionary
>>> d = {'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2}
>>> # dictionary sorted by key
>>> OrderedDict(sorted(d.items(), key=lambda t: t[0]))
OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])
>>> # dictionary sorted by value
>>> OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])
>>> # dictionary sorted by length of the key string
>>> OrderedDict(sorted(d.items(), key=lambda t: len(t[0])))
OrderedDict([('pear', 1), ('apple', 4), ('orange', 2), ('banana', 3)])
Новые отсортированные словари сохраняют свой порядок сортировки при удалении записей. Но при добавлении новых ключей ключи добавляются в конец, и сортировка не сохраняется.
Также легко создать вариант упорядоченного словаря, который запоминает порядок, в котором ключи были последними вставлены. Если новая запись перезаписывает существующую запись, исходная позиция вставки изменяется и перемещается в конец:
class LastUpdatedOrderedDict(OrderedDict):
'Store items in the order the keys were last added'
def __setitem__(self, key, value):
if key in self:
del self[key]
OrderedDict.__setitem__(self, key, value)
Упорядоченный словарь можно комбинировать с классом Counter, чтобы счётчик запоминал порядок элементов, с которыми он впервые столкнулся:
class OrderedCounter(Counter, OrderedDict):
'Counter that remembers the order elements are first encountered'
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
def __reduce__(self):
return self.__class__, (OrderedDict(self),)
6. Абстрактные базовые классы модуля Collections
Модуль collections предоставляет следующие ABC:
ABC | Наследуется от | Абстрактные методы | Методы-микшины |
|---|---|---|---|
| |||
| |||
| |||
|
| ||
| |||
| |||
|
| ||
| Наследованные методы | ||
|
| ||
| Наследованные методы | ||
|
| ||
| Наследованные методы | ||
| |||
| |||
| |||
|
-
class collections.Container -
class collections.Hashable -
class collections.Sized -
class collections.Callable -
ABC для классов, которые предоставляют соответственно методы
__contains__(),__hash__(),__len__()и__call__().
-
class collections.Iterable -
ABC для классов, которые предоставляют метод
__iter__(). См. также определение итерируемого объекта.
-
class collections.Iterator -
ABC для классов, которые предоставляют методы
__iter__()иnext(). См. также определение итератора.
-
class collections.Sequence -
class collections.MutableSequence -
ABC для неизменяемых и изменяемых последовательностей.
-
class collections.Set -
class collections.MutableSet -
ABC для неизменяемых и изменяемых множеств.
-
class collections.Mapping -
class collections.MutableMapping -
Базовые классы для чтения и изменения отображений.
-
class collections.MappingView -
class collections.ItemsView -
class collections.KeysView -
class collections.ValuesView -
Базовые классы для отображений, элементов, ключей и значений представлений.
Эти базовые классы позволяют узнать, поддерживает ли класс или экземпляр определённый функционал, например:
size = None
if isinstance(myvar, collections.Sized):
size = len(myvar)
Несколько базовых классов также полезны в качестве миксинов, что облегчает разработку классов, поддерживающих контейнерные API. Например, чтобы написать класс, поддерживающий полный Set API, достаточно реализовать три абстрактных метода: __contains__(), __iter__() и __len__(). Базовый класс предоставляет остальные методы, такие как __and__() и isdisjoint()
class ListBasedSet(collections.Set):
''' Alternate set implementation favoring space over speed
and not requiring the set elements to be hashable. '''
def __init__(self, iterable):
self.elements = lst = []
for value in iterable:
if value not in lst:
lst.append(value)
def __iter__(self):
return iter(self.elements)
def __contains__(self, value):
return value in self.elements
def __len__(self):
return len(self.elements)
s1 = ListBasedSet('abcdef')
s2 = ListBasedSet('defghi')
overlap = s1 & s2 # The __and__() method is supported automatically
Примечания по использованию Set и MutableSet как миксинов:
- Поскольку некоторые операции над множествами создают новые множества, методам миксина по умолчанию требуется способ создания новых экземпляров из итерируемого объекта. Предполагается, что у конструктора класса есть сигнатура в формате
ClassName(iterable). Это предположение вынесено во внутренний статический метод_from_iterable(), который вызываетcls(iterable)для создания нового множества. Если миксинSetиспользуется в классе с другой сигнатурой конструктора, необходимо переопределить_from_iterable()с помощью статического метода, который может создавать новые экземпляры из итерируемого аргумента. - Чтобы переопределить сравнения (вероятно, для скорости, так как семантика фиксирована), переопределите
__le__()и__ge__(), тогда остальные операции будут автоматически переопределены. - Миксин
Setпредоставляет метод_hash()для вычисления значения хеша для множества; однако,__hash__()не определен, так как не все множества хешируемы или неизменяемы. Чтобы добавить хеширование множеств с помощью миксинов, унаследуйте отSet()иHashable(), а затем определите__hash__ = Set._hash.
См. также
-
Рецепт OrderedSet для примера, построенного на
MutableSet. - Для получения дополнительной информации о базовых классах см. модуль
abcи PEP 3119.
© 2001–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/2.7/library/collections.html