На этом шаге мы рассмотрим основные возможности класса collections.ChainMap.
У вас есть много словарей или отображений, которые вы хотите логически объединить в одно отображение, чтобы выполнить некоторые операции, такие как поиск значений или проверка существования ключей.
Предположим, у вас есть два словаря:
a = {'x': 1, 'z': 3}
b = {'y': 2, 'z': 4}
А теперь предположим, что вы хотите провести поиски, в ходе которых вам нужно проверить оба словаря (то есть сначала проверить в словаре а, а потом в b, если в первом словаре искомое не найдено). Простой способ сделать это - использовать класс ChainMap из модуля collections. Например:
from collections import ChainMap c = ChainMap(a, b) print(c['x']) # Выводит 1 (из a) print(c['y']) # Выводит 2 (из b) print(c['z']) # Выводит 3 (из a)
ChainMap принимает несколько отображений и делает их логически единым целым. Однако в буквальном смысле они не сливаются. Вместо этого ChainMap просто содержит список отображений и переопределяет обычные операции над словарями для сканирования данного списка. Большинство операций работает. Например:
>>> len(c) 3 >>> list(c.keys()) ['y', 'z', 'x'] >>> list(c.values()) [2, 3, 1] >>>
В случае появления одинаковых ключей будут использованы значения из первого словаря. Например, c['z'] в примере всегда будет ссылаться на значение из словаря а, а не из b.
Операции, которые изменяют отображение, всегда действуют на первое отображение в списке. Например:
>>> c['z'] = 10 >>> c['w'] = 40 >>> del c['x'] >>> a {'z': 10, 'w': 40} >>> del c['y'] Traceback (most recent call last): . . . . KeyError: "Key not found in the first mapping: 'y'" >>>
ChainMap особенно полезны для работы со значениями, принадлежащими областям видимости, такими как переменные языка программирования (глобальные, локальные и т. п.). На самом деле даже существуют методы, которые все упрощают:
>>> values = ChainMap() >>> values['x'] = 1 >>> # Добавляем новое отображение >>> values = values.new_child() >>> values['x'] = 2 >>> # Добавляем новое отображение >>> values = values.new_child() >>> values['x'] = 3 >>> values ChainMap({'x': 3}, {'x': 2}, {'x': 1}) >>> values['x'] 3 >>> # Удаляем последнее отображение >>> values = values.parents >>> values['x'] 2 >>> # Удаляем последнее отображение >>> values = values.parents >>> values['x'] 1 >>> values ChainMap({'x': 1}) >>>
В качестве альтернативы ChainMap вы можете обдумать слияние словарей с использованием метода update(). Например:
>>> a = {'x': 1, 'z': 3}
>>> b = {'y': 2, 'z': 4}
>>> merged = dict(b)
>>> merged.update(a)
>>> merged['x']
1
>>> merged['y']
2
>>> merged['z']
3
>>>
Это работает, но требует от вас создания полностью нового объекта словаря (или необратимого изменения одного из существующих). В этом случае при изменении одного из первоначальных словарей изменения не затронут новый объект объединенного словаря. Например:
>>> a['x'] = 13 >>> merged['x'] 1 >>>
ChainMap использует первоначальные словари, поэтому не подвержен такому поведению. Например:
>>> a = {'x': 1, 'z': 3}
>>> b = {'y': 2, 'z': 4}
>>> merged = ChainMap(a, b)
>>> merged['x']
1
>>> a['x'] = 42
>>> merged['x'] # Изменение происходит и в объединенных словарях
42
>>>
Со следующего шага мы начинаем рассматривать строки и текст.