ChainMap

Класс ChainMap предназначен для быстрого связывания нескольких отображений, чтобы их можно было рассматривать как единое целое. Это намного быстрее, чем создание нового словаря и выполнение нескольких вызовов update().

Класс может использоваться для моделирования вложенных областей видимости и полезен при создании шаблонов. Класс группирует несколько словарей вместе для создания единого обновляемого представления. Если никаких словарей не передано - формируется отображение с единственным вложенным пустым словарем, так что новый ChainMap всегда имеет хотя бы одно отображение.

Cопоставления хранятся в списке. Этот список доступен и может обновлен с помощью атрибута maps. Запросы к представлению последовательно ищут во всех отображених, пока не будет найден верный ключ. Запись, обновление и удаление работают только с первым отображением.

ChainMap реализует ссылки на включения. Это значит, если одно из отображений будет обновлено, эти изменения будут отражены в ChainMap. Поддерживаются все обычные словарные методы. Кроме того, есть атрибут map, метод для создания новых подконтекстов и свойство для доступа ко всем отображениям, кроме первого.

Документация

import collections

a = {'a': 'A', 'c': 'C'}
b = {'b': 'B', 'c': 'D'}

m = collections.ChainMap(a, b)

print('Keys = {}'.format(list(m.keys())))
>>> Keys = ['b', 'c', 'a']
print('Values = {}'.format(list(m.values())))
>>> Values = ['B', 'C', 'A']
print('Items:')
for k, v in m.items():
    print('{} = {}'.format(k, v))
>>> Items:
>>> b = B
>>> c = C
>>> a = A
print('"d" in m: {}'.format(('d' in m)))
>>> "d" in m: False

Обновить значения можно как во вложениях, так и непосредственно. Во втором случае затрагивается только первое из отображений.

a = {'a': 'A', 'c': 'C'}
b = {'b': 'B', 'c': 'D'}

m = collections.ChainMap(a, b)
a['c'] = 'E'
print(m['c'])
>>> E

m['c'] = 'Z'
print(m['c'])
>>> Z
print(a)
>>> a = {'a': 'A', 'c': 'Z'}

Метод new_child() позволяет создавать новый экземпляр ChainMap с однои дополнительным отображением. Новое отображение можно заполнить сразу, передав в качестве аргумента метода.

a = {'a': 'A', 'c': 'C'}
b = {'b': 'B', 'c': 'D'}

m1 = collections.ChainMap(a, b)
m2 = m1.new_child()

print(m2)
>>> ChainMap({}, {'a': 'A', 'c': 'C'}, {'b': 'B', 'c': 'D'})

m3 = m2.new_child({'a': 'E'})
print(m3)
>>> ChainMap({'a': 'E'}, {}, {'a': 'A', 'c': 'C'}, {'b': 'B', 'c': 'D'})

Методе parents возвращает новый экземпляр ChainMap со всеми представлениями, за исключением первого.

Примеры реализации 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

[python-standart-library]