collections
— Container datatypes¶
Вихідний код: Lib/collections/__init__.py
Цей модуль реалізує спеціалізовані типи даних контейнерів, що є альтернативою вбудованим контейнерам загального призначення Python, dict
, list
, set
і tuple
.
функція фабрики для створення підкласів кортежів з іменованими полями |
|
контейнер, схожий на список, із швидким додаванням і вискакуванням на обох кінцях |
|
dict-подібний клас для створення єдиного перегляду кількох відображень |
|
dict subclass for counting hashable objects |
|
підклас dict, який запам’ятовує додані записи порядку |
|
підклас dict, який викликає фабричну функцію для надання відсутніх значень |
|
обгортка навколо об’єктів словника для легшого створення підкласів dict |
|
обгортка навколо об’єктів списку для легшого створення підкласів списку |
|
обгортка навколо рядкових об’єктів для легшого створення підкласів рядків |
ChainMap
об’єкти¶
Нове в версії 3.3.
Клас ChainMap
надається для швидкого зв’язування кількох відображень, щоб їх можна було розглядати як єдине ціле. Часто це набагато швидше, ніж створення нового словника та виконання кількох викликів update()
.
Клас можна використовувати для імітації вкладених областей і корисний у створенні шаблонів.
- class collections.ChainMap(*maps)¶
ChainMap
групує кілька dicts або інших відображень разом, щоб створити єдине оновлюване подання. Якщо maps не вказано, надається єдиний порожній словник, щоб новий ланцюжок завжди мав принаймні одне відображення.Базові відображення зберігаються в списку. Цей список є загальнодоступним, і до нього можна отримати доступ або оновити за допомогою атрибута maps. Іншої держави немає.
Пошуки послідовно шукають базові відображення, доки не буде знайдено ключ. Навпаки, записи, оновлення та видалення діють лише на першому відображенні.
ChainMap
включає базові відображення за посиланням. Отже, якщо одне з базових відображень буде оновлено, ці зміни буде відображено вChainMap
.Підтримуються всі звичайні словникові методи. Крім того, існує атрибут maps, метод для створення нових підконтекстів і властивість для доступу до всіх відображень, крім першого:
- maps¶
Список відображень, який можна оновлювати користувачем. Список упорядковано від першого до останнього. Це єдиний стан, який зберігається, і його можна змінити, щоб змінити зіставлення, які шукаються. Список завжди повинен містити принаймні одне зіставлення.
- new_child(m=None, **kwargs)¶
Повертає новий
ChainMap
, який містить нову карту, за якою слідують усі карти в поточному екземплярі. Якщо вказаноm
, воно стає новою картою на початку списку зіставлень; якщо не вказано, використовується порожній dict, так що викликd.new_child()
еквівалентний:ChainMap({}, *d.maps)
. Якщо вказано будь-які аргументи ключового слова, вони оновлюють передану карту або новий порожній dict. Цей метод використовується для створення підконтекстів, які можна оновлювати без зміни значень у будь-якому з батьківських відображень.Змінено в версії 3.4: Додано необов’язковий параметр
m
.Змінено в версії 3.10: Додано підтримку аргументів ключових слів.
- parents¶
Властивість, що повертає новий
ChainMap
, що містить усі карти в поточному екземплярі, крім першої. Це корисно для пропуску першої карти в пошуку. Випадки використання схожі на випадки використання ключового словаnonlocal
, що використовується у вкладених областях. Випадки використання також аналогічні використанню вбудованої функціїsuper()
. Посилання наd.parents
еквівалентне:ChainMap(*d.maps[1:])
.
Note, the iteration order of a
ChainMap()
is determined by scanning the mappings last to first:>>> baseline = {'music': 'bach', 'art': 'rembrandt'} >>> adjustments = {'art': 'van gogh', 'opera': 'carmen'} >>> list(ChainMap(adjustments, baseline)) ['music', 'art', 'opera']
Це дає такий самий порядок, як і серія викликів
dict.update()
, починаючи з останнього відображення:>>> combined = baseline.copy() >>> combined.update(adjustments) >>> list(combined) ['music', 'art', 'opera']
Змінено в версії 3.9: Додано підтримку операторів
|
і|=
, указаних у PEP 584.
Дивись також
MultiContext class у пакеті Enthought CodeTools має опції для підтримки запису в будь-яке відображення в ланцюжку.
Клас контексту Django для створення шаблонів — це ланцюжок відображень лише для читання. Він також має функцію надсилання та витягування контекстів, подібних до методу
new_child()
і властивостіparents
.The Nested Contexts recipe has options to control whether writes and other mutations apply only to the first mapping or to any mapping in the chain.
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
Counter
is adict
subclass 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. TheCounter
class is similar to bags or multisets in other languages.Елементи підраховуються з iterable або ініціалізуються з іншого mapping (або лічильника):
>>> c = Counter() # a new, empty counter >>> c = Counter('gallahad') # a new counter from an iterable >>> c = Counter({'red': 4, 'blue': 2}) # a new counter from a mapping >>> c = Counter(cats=4, dogs=8) # a new counter from keyword args
Об’єкти лічильників мають інтерфейс словника, за винятком того, що вони повертають нульову кількість для відсутніх елементів замість того, щоб викликати
KeyError
:>>> c = Counter(['eggs', 'ham']) >>> c['bacon'] # count of a missing element is zero 0
Встановлення лічильника на нуль не видаляє елемент із лічильника. Використовуйте
del
, щоб видалити його повністю:>>> c['sausage'] = 0 # counter entry with a zero count >>> del c['sausage'] # del actually removes the entry
Нове в версії 3.1.
Змінено в версії 3.7: Як підклас
dict
,Counter
успадкував можливість запам’ятовувати порядок вставки. Математичні операції над об’єктами Counter також зберігають порядок. Результати впорядковуються відповідно до того, коли елемент вперше зустрічається в лівому операнді, а потім у порядку зустрічі в правому операнді.Об’єкти лічильників підтримують додаткові методи, окрім тих, що доступні для всіх словників:
- elements()¶
Повертає ітератор над елементами, повторюючи кожен стільки разів, скільки його кількість. Елементи повертаються в тому порядку, в якому вони зустрічаються першими. Якщо кількість елемента менше одиниці,
elements()
проігнорує його.>>> c = Counter(a=4, b=2, c=0, d=-2) >>> sorted(c.elements()) ['a', 'a', 'a', 'a', 'b', 'b']
- most_common([n])¶
Повертає список з n найпоширеніших елементів і їх підрахунок від найбільш поширених до найменших. Якщо n пропущено або
None
,most_common()
повертає всі елементи в лічильнику. Елементи з рівною кількістю впорядковуються в порядку, коли вони зустрічаються першими:>>> Counter('abracadabra').most_common(3) [('a', 5), ('b', 2), ('r', 2)]
- subtract([iterable-or-mapping])¶
Елементи віднімаються з iterable або з іншого mapping (або лічильника). Подібно до
dict.update()
, але кількість віднімає, а не замінює. І входи, і виходи можуть бути нульовими або негативними.>>> c = Counter(a=4, b=2, c=0, d=-2) >>> d = Counter(a=1, b=2, c=3, d=4) >>> c.subtract(d) >>> c Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})
Нове в версії 3.2.
- total()¶
Обчисліть суму підрахунків.
>>> c = Counter(a=10, b=5, c=0) >>> c.total() 15
Нове в версії 3.10.
Звичайні методи словника доступні для об’єктів
Counter
, за винятком двох, які працюють по-різному для лічильників.- update([iterable-or-mapping])¶
Елементи підраховуються від iterable або add-in від іншого mapping (або лічильника). Як
dict.update()
, але додає лічильники замість їх заміни. Крім того, очікується, що iterable буде послідовністю елементів, а не послідовністю пар(ключ, значення)
.
Лічильники підтримують розширені оператори порівняння для зв’язків рівності, підмножини та надмножини: ==
, !=
, <
, <=
, >
, >=
. Усі ці тести розглядають відсутні елементи як такі, що мають нульову кількість, тому Counter(a=1) == Counter(a=1, b=0)
повертає true.
Змінено в версії 3.10: Додано розширені операції порівняння.
Змінено в версії 3.10: У тестах на рівність відсутні елементи розглядаються як такі, що мають нульову кількість. Раніше Counter(a=3)
і Counter(a=3, b=0)
вважалися різними.
Загальні шаблони для роботи з об’єктами Counter
:
c.total() # total of all counts
c.clear() # reset all counts
list(c) # list unique elements
set(c) # convert to a set
dict(c) # convert to a regular dictionary
c.items() # convert to a list of (elem, cnt) pairs
Counter(dict(list_of_pairs)) # convert from a list of (elem, cnt) pairs
c.most_common()[:-n-1:-1] # n least common elements
+c # remove zero and negative counts
Передбачено кілька математичних операцій для об’єднання об’єктів Counter
для створення мультимножин (лічильників, які мають кількість, більшу за нуль). Додавання та віднімання поєднують лічильники шляхом додавання або віднімання підрахунків відповідних елементів. Перетин і об’єднання повертають мінімальне та максимальне значення відповідних підрахунків. Рівність і включення порівнюють відповідні підрахунки. Кожна операція може приймати вхідні дані зі знаком підрахунків, але вихід виключатиме результати з нульовими чи меншими значеннями.
>>> c = Counter(a=3, b=1)
>>> d = Counter(a=1, b=2)
>>> c + d # add two counters together: c[x] + d[x]
Counter({'a': 4, 'b': 3})
>>> c - d # subtract (keeping only positive counts)
Counter({'a': 2})
>>> c & d # intersection: min(c[x], d[x])
Counter({'a': 1, 'b': 1})
>>> c | d # union: max(c[x], d[x])
Counter({'a': 3, 'b': 2})
>>> c == d # equality: c[x] == d[x]
False
>>> c <= d # inclusion: c[x] <= d[x]
False
Унарне додавання та віднімання — це ярлики для додавання порожнього лічильника або віднімання з порожнього лічильника.
>>> c = Counter(a=2, b=-4)
>>> +c
Counter({'a': 2})
>>> -c
Counter({'b': 4})
Нове в версії 3.3: Додано підтримку унарних операцій плюс, унарний мінус і мультимножинних операцій на місці.
Примітка
Лічильники були в основному розроблені для роботи з позитивними цілими числами для представлення поточних підрахунків; однак було вжито заходів для того, щоб без потреби не виключити випадки використання, які потребують інших типів або від’ємних значень. Щоб допомогти з цими випадками використання, у цьому розділі описані мінімальні обмеження діапазону та типу.
Сам клас
Counter
є підкласом словника без обмежень щодо його ключів і значень. Значення мають бути числами, що представляють кількість, але ви можете зберігати будь-що в полі значення.Метод
most_common()
вимагає лише того, щоб значення можна було впорядкувати.Для операцій на місці, таких як
c[key] += 1
, тип значення потребує лише підтримки додавання та віднімання. Отже, дроби, числа з плаваючою точкою та десяткові дроби працюватимуть, а від’ємні значення підтримуються. Те ж саме вірно дляupdate()
іsubtract()
, які дозволяють від’ємні та нульові значення як для входів, так і для виходів.Мультимножинні методи призначені лише для випадків використання з позитивними значеннями. Вхідні дані можуть бути від’ємними або нульовими, але створюються лише виходи з позитивними значеннями. Немає обмежень щодо типів, але тип значення має підтримувати додавання, віднімання та порівняння.
Метод
elements()
вимагає підрахунку цілих чисел. Він ігнорує нульові та негативні значення.
Дивись також
Клас сумки у Smalltalk.
Запис у Вікіпедії для Мультимножини.
C++ multisets посібник із прикладами.
Про математичні операції над мультимножинами та випадки їх використання див. Knuth, Donald. Мистецтво комп’ютерного програмування, том II, розділ 4.6.3, вправа 19.
Щоб перерахувати всі різні мультимножини заданого розміру над заданим набором елементів, перегляньте
itertools.combinations_with_replacement()
:map(Counter, combinations_with_replacement('ABC', 2)) # --> AA AB AC BB BC CC
deque
об’єкти¶
- class collections.deque([iterable[, maxlen]])¶
Повертає новий об’єкт deque, ініціалізований зліва направо (за допомогою
append()
) з даними з iterable. Якщо iterable не вказано, нова двочерга порожня.Deques are a generalization of stacks and queues (the name is pronounced «deck» and is short for «double-ended queue»). Deques support thread-safe, memory efficient appends and pops from either side of the deque with approximately the same O(1) performance in either direction.
Though
list
objects support similar operations, they are optimized for fast fixed-length operations and incur O(n) memory movement costs forpop(0)
andinsert(0, v)
operations which change both the size and position of the underlying data representation.Якщо maxlen не вказано або має значення
None
, дві версії можуть зростати до довільної довжини. В іншому випадку двочерга обмежена до вказаної максимальної довжини. Коли двочерга обмеженої довжини заповнюється, коли додаються нові елементи, відповідна кількість елементів відкидається з протилежного кінця. Обмежена довжина двох рядків забезпечує функціональність, подібну до фільтраtail
в Unix. Вони також корисні для відстеження транзакцій та інших наборів даних, де цікаві лише останні дії.Об’єкти Deque підтримують такі методи:
- append(x)¶
Додайте x до правої сторони дека.
- appendleft(x)¶
Додайте x до лівої сторони дека.
- clear()¶
Видаліть усі елементи з двоканального ряду, залишивши його довжиною 0.
- copy()¶
Створіть поверхневу копію deque.
Нове в версії 3.5.
- count(x)¶
Підрахуйте кількість елементів deque, що дорівнює x.
Нове в версії 3.2.
- extend(iterable)¶
Розширте праву частину двоканального ряду, додавши елементи з ітерованого аргументу.
- extendleft(iterable)¶
Розширте ліву сторону двостороннього коду, додавши елементи з iterable. Зауважте, що серія лівих додань призводить до зміни порядку елементів у повторюваному аргументі.
- index(x[, start[, stop]])¶
Повертає позицію x у черзі (за індексом start і перед індексом stop). Повертає перший збіг або викликає
ValueError
, якщо не знайдено.Нове в версії 3.5.
- insert(i, x)¶
Вставте x у рядок у позицію i.
Якщо вставка призведе до того, що обмежена двочерга виросте за межі maxlen, виникає
IndexError
.Нове в версії 3.5.
- pop()¶
Видаліть і поверніть елемент з правого боку двоканальної таблиці. Якщо немає елементів, викликає
IndexError
.
- popleft()¶
Видаліть і поверніть елемент з лівої сторони двосторонньої версії. Якщо немає елементів, викликає
IndexError
.
- remove(value)¶
Видаліть перше входження значення. Якщо не знайдено, викликає
ValueError
.
- reverse()¶
Перевернути елементи дек-версії на місці, а потім повернути
None
.Нове в версії 3.2.
- rotate(n=1)¶
Поверніть двічі n кроків праворуч. Якщо n від’ємне, поверніть ліворуч.
Якщо двочерга не порожня, поворот на один крок праворуч еквівалентний d.appendleft(d.pop()) , а поворот на один крок ліворуч еквівалентний d.append(d.popleft ())``.
Об’єкти Deque також надають один атрибут лише для читання:
- maxlen¶
Максимальний розмір двочергового рядка або
None
, якщо необмежений.Нове в версії 3.1.
In addition to the above, deques support iteration, pickling, len(d)
,
reversed(d)
, copy.copy(d)
, copy.deepcopy(d)
, membership testing with
the in
operator, and subscript references such as d[0]
to access
the first element. Indexed access is O(1) at both ends but slows to O(n) in
the middle. For fast random access, use lists instead.
Починаючи з версії 3.5, deques підтримують __add__()
, __mul__()
і __imul__()
.
приклад:
>>> from collections import deque
>>> d = deque('ghi') # make a new deque with three items
>>> for elem in d: # iterate over the deque's elements
... print(elem.upper())
G
H
I
>>> d.append('j') # add a new entry to the right side
>>> d.appendleft('f') # add a new entry to the left side
>>> d # show the representation of the deque
deque(['f', 'g', 'h', 'i', 'j'])
>>> d.pop() # return and remove the rightmost item
'j'
>>> d.popleft() # return and remove the leftmost item
'f'
>>> list(d) # list the contents of the deque
['g', 'h', 'i']
>>> d[0] # peek at leftmost item
'g'
>>> d[-1] # peek at rightmost item
'i'
>>> list(reversed(d)) # list the contents of a deque in reverse
['i', 'h', 'g']
>>> 'h' in d # search the deque
True
>>> d.extend('jkl') # add multiple elements at once
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> d.rotate(1) # right rotation
>>> d
deque(['l', 'g', 'h', 'i', 'j', 'k'])
>>> d.rotate(-1) # left rotation
>>> d
deque(['g', 'h', 'i', 'j', 'k', 'l'])
>>> deque(reversed(d)) # make a new deque in reverse order
deque(['l', 'k', 'j', 'i', 'h', 'g'])
>>> d.clear() # empty the deque
>>> d.pop() # cannot pop from an empty deque
Traceback (most recent call last):
File "<pyshell#6>", line 1, in -toplevel-
d.pop()
IndexError: pop from an empty deque
>>> d.extendleft('abc') # extendleft() reverses the input order
>>> d
deque(['c', 'b', 'a'])
deque
Рецепти¶
У цьому розділі показано різні підходи до роботи з 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)
Інший підхід до використання двох блоків полягає в підтримці послідовності нещодавно доданих елементів шляхом додавання праворуч і висування ліворуч:
def moving_average(iterable, n=3):
# moving_average([40, 30, 50, 46, 39, 44]) --> 40.0 42.0 45.0 43.0
# https://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
нарізки та видалення. Наприклад, чиста реалізація del d[n]
на Python покладається на метод rotate()
для позиціонування елементів, які потрібно відкрити:
def delete_nth(d, n):
d.rotate(-n)
d.popleft()
d.rotate(n)
Щоб реалізувати нарізку deque
, скористайтеся подібним підходом, застосовуючи rotate()
, щоб перемістити цільовий елемент у ліву сторону від deque. Видаліть старі записи за допомогою popleft()
, додайте нові за допомогою extend()
, а потім змініть чергування. З незначними варіаціями цього підходу легко реалізувати маніпуляції стеком у стилі Forth, такі як dup
, drop
, swap
, over
, pick
, rot
і roll
.
defaultdict
об’єкти¶
- class collections.defaultdict(default_factory=None, /[, ...])¶
Повернути новий об’єкт, схожий на словник.
defaultdict
є підкласом вбудованого класуdict
. Він замінює один метод і додає одну змінну екземпляра, доступну для запису. Інші функції такі ж, як і для класуdict
, і тут не описані.Перший аргумент надає початкове значення для атрибута
default_factory
; за замовчуваннямNone
. Усі решта аргументів обробляються так само, як якщо б вони були передані конструкторуdict
, включаючи аргументи ключових слів.Об’єкти
defaultdict
підтримують наступний метод на додаток до стандартних операційdict
:- __missing__(key)¶
Якщо атрибут
default_factory
має значенняNone
, це викликає виключенняKeyError
з key як аргументом.Якщо
default_factory
не єNone
, він викликається без аргументів, щоб надати значення за замовчуванням для даного ключа, це значення вставляється в словник для ключа та повертається.Якщо виклик
default_factory
викликає виняток, цей виняток поширюється без змін.This method is called by the
__getitem__()
method of thedict
class when the requested key is not found; whatever it returns or raises is then returned or raised by__getitem__()
.Note that
__missing__()
is not called for any operations besides__getitem__()
. This means thatget()
will, like normal dictionaries, returnNone
as a default rather than usingdefault_factory
.
Об’єкти
defaultdict
підтримують таку змінну екземпляра:- default_factory¶
Цей атрибут використовується методом
__missing__()
; він ініціалізується від першого аргументу до конструктора, якщо він присутній, або доNone
, якщо його немає.
Змінено в версії 3.9: Додано оператори злиття (
|
) і оновлення (|=
), указані в PEP 584.
defaultdict
Приклади¶
Використовуючи list
як default_factory
, можна легко згрупувати послідовність пар ключ-значення в словник списків:
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
... d[k].append(v)
...
>>> sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
Коли кожен ключ зустрічається вперше, його ще немає у відображенні; тому запис створюється автоматично за допомогою функції default_factory
, яка повертає порожній list
. Потім операція list.append()
додає значення до нового списку. Коли ключі зустрічаються знову, пошук триває нормально (повертається список для цього ключа), а операція list.append()
додає інше значення до списку. Ця техніка простіша та швидша, ніж еквівалентна техніка з використанням dict.setdefault()
:
>>> d = {}
>>> for k, v in s:
... d.setdefault(k, []).append(v)
...
>>> sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
Встановлення default_factory
на int
робить defaultdict
корисним для підрахунку (як сумка або мультинабір в інших мовах):
>>> s = 'mississippi'
>>> d = defaultdict(int)
>>> for k in s:
... d[k] += 1
...
>>> sorted(d.items())
[('i', 4), ('m', 1), ('p', 2), ('s', 4)]
Коли буква зустрічається вперше, вона відсутня у відображенні, тому функція default_factory
викликає int()
, щоб надати нульову кількість за умовчанням. Потім операція збільшення створює кількість для кожної літери.
Функція int()
, яка завжди повертає нуль, є лише окремим випадком постійних функцій. Швидший і більш гнучкий спосіб створення постійних функцій полягає у використанні лямбда-функції, яка може надати будь-яке постійне значення (не лише нуль):
>>> def constant_factory(value):
... return lambda: value
>>> d = defaultdict(constant_factory('<missing>'))
>>> d.update(name='John', action='ran')
>>> '%(name)s %(action)s to %(object)s' % d
'John ran to <missing>'
Встановлення default_factory
на set
робить defaultdict
корисним для створення словника наборів:
>>> s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
>>> d = defaultdict(set)
>>> for k, v in s:
... d[k].add(v)
...
>>> sorted(d.items())
[('blue', {2, 4}), ('red', {1, 3})]
namedtuple()
Фабрична функція для кортежів з іменованими полями¶
Іменовані кортежі призначають значення кожній позиції в кортежі та забезпечують більш читабельний самодокументований код. Їх можна використовувати скрізь, де використовуються звичайні кортежі, і вони додають можливість доступу до полів за назвою замість індексу позиції.
- collections.namedtuple(typename, field_names, *, rename=False, defaults=None, module=None)¶
Повертає новий підклас кортежу з назвою typename. Новий підклас використовується для створення кортежних об’єктів, які мають поля, доступні за допомогою пошуку атрибутів, а також які можна індексувати та повторювати. Екземпляри підкласу також мають корисний рядок документації (з назвою типу та іменами полів) і корисний метод
__repr__()
, який перераховує вміст кортежу у форматіім'я=значення
.Імена_полів — це послідовність рядків, наприклад
['x', 'y']
. Крім того, назви_полів можуть бути одним рядком із назвою кожного поля, розділеного пробілами та/або комами, наприклад'x y'
або'x, y'
.Для імені поля можна використовувати будь-який дійсний ідентифікатор Python, за винятком імен, що починаються з підкреслення. Дійсні ідентифікатори складаються з літер, цифр і підкреслення, але не починаються з цифри або підкреслення і не можуть бути
keyword
, таким як клас, для, повернення, глобальний, перехід , або підняти.Якщо rename має значення true, недійсні назви полів автоматично замінюються позиційними іменами. Наприклад,
['abc', 'def', 'ghi', 'abc']
перетворюється на['abc', '_1', 'ghi', '_3']
, усуваючи ключове словоdef
і повторюване ім’я поляabc
.defaults може бути
None
або iterable значень за замовчуванням. Оскільки поля зі значенням за замовчуванням мають бути після будь-яких полів без значення за замовчуванням, за замовчуванням застосовуються до крайніх правих параметрів. Наприклад, якщо імена полів['x', 'y', 'z']
, а значення за умовчанням(1, 2)
, тодіx
буде обов’язковим аргументом,y
за замовчуванням буде1
, аz
буде2
.Якщо визначено module, атрибут
__module__
названого кортежу встановлюється на це значення.Іменовані екземпляри кортежу не мають словників для кожного екземпляра, тому вони легкі та не вимагають більше пам’яті, ніж звичайні кортежі.
Щоб підтримувати маринування, іменований клас кортежу має бути призначений змінній, яка відповідає typename.
Змінено в версії 3.1: Додано підтримку перейменування.
Змінено в версії 3.6: Параметри verbose і rename стали аргументами лише для ключових слів.
Змінено в версії 3.6: Додано параметр module.
Змінено в версії 3.7: Видалено параметр verbose і атрибут
_source
.Змінено в версії 3.7: Додано параметр defaults і атрибут
_field_defaults
.
>>> # Basic example
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(11, y=22) # instantiate with positional or keyword arguments
>>> p[0] + p[1] # indexable like the plain tuple (11, 22)
33
>>> x, y = p # unpack like a regular tuple
>>> x, y
(11, 22)
>>> p.x + p.y # fields also accessible by name
33
>>> p # readable __repr__ with a name=value style
Point(x=11, y=22)
Іменовані кортежі особливо корисні для призначення імен полів кортежам результатів, які повертаються модулями csv
або sqlite3
:
EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')
import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))):
print(emp.name, emp.title)
import sqlite3
conn = sqlite3.connect('/companydata')
cursor = conn.cursor()
cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
for emp in map(EmployeeRecord._make, cursor.fetchall()):
print(emp.name, emp.title)
На додаток до методів, успадкованих від кортежів, іменовані кортежі підтримують три додаткові методи та два атрибути. Щоб запобігти конфліктам імен полів, імена методів і атрибутів починаються зі знака підкреслення.
- classmethod somenamedtuple._make(iterable)¶
Метод класу, який створює новий екземпляр із існуючої послідовності або повторюється.
>>> t = [11, 22] >>> Point._make(t) Point(x=11, y=22)
- somenamedtuple._asdict()¶
Повертає новий
dict
, який зіставляє назви полів з відповідними значеннями:>>> p = Point(x=11, y=22) >>> p._asdict() {'x': 11, 'y': 22}
Змінено в версії 3.1: Повертає
OrderedDict
замість звичайногоdict
.Змінено в версії 3.8: Повертає звичайний
dict
замістьOrderedDict
. Починаючи з Python 3.7, звичайні dicts гарантовано будуть упорядковані. Якщо потрібні додаткові функціїOrderedDict
, запропонованим виправленням є приведення результату до потрібного типу:OrderedDict(nt._asdict())
.
- somenamedtuple._replace(**kwargs)¶
Повертає новий екземпляр іменованого кортежу, замінюючи вказані поля новими значеннями:
>>> p = Point(x=11, y=22) >>> p._replace(x=33) Point(x=33, y=22) >>> for partnum, record in inventory.items(): ... inventory[partnum] = record._replace(price=newprices[partnum], timestamp=time.now())
- somenamedtuple._fields¶
Кортеж рядків із переліком імен полів. Корисно для самоаналізу та для створення нових іменованих типів кортежів із існуючих іменованих кортежів.
>>> p._fields # view the field names ('x', 'y') >>> Color = namedtuple('Color', 'red green blue') >>> Pixel = namedtuple('Pixel', Point._fields + Color._fields) >>> Pixel(11, 22, 128, 255, 0) Pixel(x=11, y=22, red=128, green=255, blue=0)
- somenamedtuple._field_defaults¶
Словник зіставляє назви полів зі значеннями за замовчуванням.
>>> Account = namedtuple('Account', ['type', 'balance'], defaults=[0]) >>> Account._field_defaults {'balance': 0} >>> Account('premium') Account(type='premium', balance=0)
Щоб отримати поле, ім’я якого зберігається в рядку, використовуйте функцію getattr()
:
>>> getattr(p, 'x')
11
Щоб перетворити словник на іменований кортеж, використовуйте оператор подвійної зірочки (як описано в Розпакування списків аргументів):
>>> d = {'x': 11, 'y': 22}
>>> Point(**d)
Point(x=11, y=22)
Оскільки іменований кортеж є звичайним класом Python, його легко додати або змінити функціональність за допомогою підкласу. Ось як додати обчислюване поле та формат друку з фіксованою шириною:
>>> class Point(namedtuple('Point', ['x', 'y'])):
... __slots__ = ()
... @property
... def hypot(self):
... return (self.x ** 2 + self.y ** 2) ** 0.5
... def __str__(self):
... return 'Point: x=%6.3f y=%6.3f hypot=%6.3f' % (self.x, self.y, self.hypot)
>>> for p in Point(3, 4), Point(14, 5/7):
... print(p)
Point: x= 3.000 y= 4.000 hypot= 5.000
Point: x=14.000 y= 0.714 hypot=14.018
Показаний вище підклас встановлює __slots__
на порожній кортеж. Це допомагає підтримувати низькі вимоги до пам’яті, запобігаючи створенню словників примірників.
Підкласи не корисні для додавання нових збережених полів. Замість цього просто створіть новий іменований тип кортежу з атрибута _fields
:
>>> Point3D = namedtuple('Point3D', Point._fields + ('z',))
Рядки документів можна налаштувати шляхом прямого призначення полів __doc__
:
>>> Book = namedtuple('Book', ['id', 'title', 'authors'])
>>> Book.__doc__ += ': Hardcover book in active collection'
>>> Book.id.__doc__ = '13-digit ISBN'
>>> Book.title.__doc__ = 'Title of first printing'
>>> Book.authors.__doc__ = 'List of authors sorted by last name'
Змінено в версії 3.5: Документаційні рядки властивостей стали доступними для запису.
Дивись також
Дивіться
typing.NamedTuple
, щоб дізнатися, як додати підказки типу для іменованих кортежів. Він також забезпечує елегантну нотацію за допомогою ключового словаclass
:class Component(NamedTuple): part_number: int weight: float description: Optional[str] = None
Перегляньте
types.SimpleNamespace()
для змінного простору імен, заснованого на базовому словнику замість кортежу.Модуль
dataclasses
надає декоратор і функції для автоматичного додавання згенерованих спеціальних методів до визначених користувачем класів.
OrderedDict
об’єкти¶
Упорядковані словники схожі на звичайні словники, але мають деякі додаткові можливості, пов’язані з операціями впорядкування. Тепер вони стали менш важливими, оскільки вбудований клас dict
отримав можливість запам’ятовувати порядок вставки (ця нова поведінка стала гарантованою в Python 3.7).
Деякі відмінності від dict
все ще залишаються:
Звичайний
dict
був розроблений, щоб дуже добре виконувати операції відображення. Відстеження порядку вставки було другорядним.OrderedDict
був розроблений, щоб добре справлятися з операціями зміни порядку. Ефективність простору, швидкість ітерації та продуктивність операцій оновлення були другорядними.Алгоритм
OrderedDict
може виконувати часті операції зміни порядку краще, ніжdict
. Як показано в наведених нижче рецептах, це робить його придатним для реалізації різних видів кешів LRU.Операція рівності для
OrderedDict
перевіряє відповідність порядку.Звичайний
dict
може емулювати чутливий до порядку тест рівності зp == q і all(k1 == k2 для k1, k2 в zip(p, q))
.Метод
popitem()
OrderedDict
має інший підпис. Він приймає необов’язковий аргумент, щоб вказати, який елемент витягується.Звичайний
dict
може емулювати OrderedDictod.popitem(last=True)
за допомогоюd.popitem()
, який гарантовано відкриває крайній правий (останній) елемент.Звичайний
dict
може емулювати OrderedDictod.popitem(last=False)
з(k := next(iter(d)), d.pop(k))
, який повертатиме і видаліть крайній лівий (перший) елемент, якщо він існує.OrderedDict
має методmove_to_end()
для ефективного переміщення елемента в кінцеву точку.Звичайний
dict
може емулювати OrderedDictod.move_to_end(k, last=True)
зd[k] = d.pop(k)
, який переміщуватиме ключ і його пов’язане значення до крайньої правої (останньої) позиції.Звичайний
dict
не має ефективного еквівалента для OrderedDictod.move_to_end(k, last=False)
, який переміщує ключ і пов’язане з ним значення в крайню ліву (першу) позицію.До Python 3.8
dict
не мав методу__reversed__()
.
- class collections.OrderedDict([items])¶
Повертає екземпляр підкласу
dict
, який має спеціалізовані методи для зміни порядку словника.Нове в версії 3.1.
- popitem(last=True)¶
Метод
popitem()
для впорядкованих словників повертає та видаляє пару (ключ, значення). Пари повертаються в порядку LIFO, якщо останній має значення true, або FIFO, якщо значення false.
- move_to_end(key, last=True)¶
Перемістіть наявний ключ у будь-який кінець упорядкованого словника. Елемент переміщується в правий кінець, якщо last має значення true (за замовчуванням), або на початок, якщо last має значення false. Викликає
KeyError
, якщо ключ не існує:>>> d = OrderedDict.fromkeys('abcde') >>> d.move_to_end('b') >>> ''.join(d) 'acdeb' >>> d.move_to_end('b', last=False) >>> ''.join(d) 'bacde'
Нове в версії 3.2.
На додаток до звичайних методів відображення, упорядковані словники також підтримують зворотну ітерацію за допомогою reversed()
.
Перевірки рівності між об’єктами OrderedDict
чутливі до порядку та реалізовані як list(od1.items())==list(od2.items())
. Перевірки рівності між об’єктами OrderedDict
та іншими об’єктами Mapping
не залежать від порядку, як і звичайні словники. Це дозволяє замінювати об’єкти OrderedDict
будь-де, де використовується звичайний словник.
Змінено в версії 3.5: Елементи, ключі та значення views OrderedDict
тепер підтримують зворотну ітерацію за допомогою reversed()
.
Змінено в версії 3.6: З прийняттям PEP 468 зберігається порядок для аргументів ключових слів, які передаються конструктору OrderedDict
і його методу update()
.
Змінено в версії 3.9: Додано оператори злиття (|
) і оновлення (|=
), указані в PEP 584.
OrderedDict
Приклади та рецепти¶
Легко створити впорядкований варіант словника, який запам’ятовує порядок останнього введення ключів. Якщо новий запис перезаписує існуючий запис, початкова позиція вставки змінюється та переміщується в кінець:
class LastUpdatedOrderedDict(OrderedDict):
'Store items in the order the keys were last added'
def __setitem__(self, key, value):
super().__setitem__(key, value)
self.move_to_end(key)
OrderedDict
також буде корисним для реалізації варіантів functools.lru_cache()
:
from time import time
class TimeBoundedLRU:
"LRU Cache that invalidates and refreshes old entries."
def __init__(self, func, maxsize=128, maxage=30):
self.cache = OrderedDict() # { args : (timestamp, result)}
self.func = func
self.maxsize = maxsize
self.maxage = maxage
def __call__(self, *args):
if args in self.cache:
self.cache.move_to_end(args)
timestamp, result = self.cache[args]
if time() - timestamp <= self.maxage:
return result
result = self.func(*args)
self.cache[args] = time(), result
if len(self.cache) > self.maxsize:
self.cache.popitem(0)
return result
class MultiHitLRUCache:
""" LRU cache that defers caching a result until
it has been requested multiple times.
To avoid flushing the LRU cache with one-time requests,
we don't cache until a request has been made more than once.
"""
def __init__(self, func, maxsize=128, maxrequests=4096, cache_after=1):
self.requests = OrderedDict() # { uncached_key : request_count }
self.cache = OrderedDict() # { cached_key : function_result }
self.func = func
self.maxrequests = maxrequests # max number of uncached requests
self.maxsize = maxsize # max number of stored return values
self.cache_after = cache_after
def __call__(self, *args):
if args in self.cache:
self.cache.move_to_end(args)
return self.cache[args]
result = self.func(*args)
self.requests[args] = self.requests.get(args, 0) + 1
if self.requests[args] <= self.cache_after:
self.requests.move_to_end(args)
if len(self.requests) > self.maxrequests:
self.requests.popitem(0)
else:
self.requests.pop(args, None)
self.cache[args] = result
if len(self.cache) > self.maxsize:
self.cache.popitem(0)
return result
UserDict
об’єкти¶
Клас UserDict
діє як оболонка навколо об’єктів словника. Потреба в цьому класі була частково витіснена можливістю створювати підклас безпосередньо з dict
; однак з цим класом може бути легше працювати, оскільки базовий словник доступний як атрибут.
- class collections.UserDict([initialdata])¶
Клас, який імітує словник. Вміст екземпляра зберігається у звичайному словнику, який доступний через атрибут
data
екземплярівUserDict
. Якщо надано initialdata,data
ініціалізується його вмістом; зауважте, що посилання на ініціальні дані не буде збережено, що дозволить використовувати його для інших цілей.На додаток до підтримки методів і операцій зіставлення, екземпляри
UserDict
забезпечують такий атрибут:
UserList
об’єкти¶
Цей клас діє як оболонка навколо об’єктів списку. Це корисний базовий клас для ваших власних спископодібних класів, які можуть успадковувати їх і перевизначати існуючі методи або додавати нові. Таким чином можна додавати нові моделі поведінки до списків.
Потреба в цьому класі була частково витіснена можливістю створювати підкласи безпосередньо з list
; однак з цим класом може бути легше працювати, оскільки базовий список доступний як атрибут.
- class collections.UserList([list])¶
Клас, що імітує список. Вміст екземпляра зберігається у звичайному списку, який доступний через атрибут
data
екземплярівUserList
. Вміст екземпляра спочатку встановлено як копія списку, за замовчуванням — порожній список[]
. 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
.