ChainMap - ricerca su molteplici dizionari
Scopo: La classe ChainMap
gestisce una sequenza di dizionari, scorrendoli in ordine per cercare dei valori associati alle chiavi.
La classe ChainMap
gestisce una sequenza di dizionari, scorrendoli in ordine per cercare dei valori associati alle chiavi. ChainMap
è un buon contenitore di "contesto", visto che può essere trattato come uno stack con le modifiche che si manifestano mentre lo stack cresce, poi si scaricano mentre lo stack rimpicciolisce.
Accesso ai Valori
Per accedere ai valori, ChainMap
supporta la stessa API di un normale dizionario.
# collections_chainmap_read.py
import collections
a = {'a': 'A', 'c': 'C'}
b = {'b': 'B', 'c': 'D'}
m = collections.ChainMap(a, b)
print('Valori individuali')
print('a = {}'.format(m['a']))
print('b = {}'.format(m['b']))
print('c = {}'.format(m['c']))
print()
print('Chiavi = {}'.format(list(m.keys())))
print('Valori = {}'.format(list(m.values())))
print()
print('Elementi:')
for k, v in m.items():
print('{} = {}'.format(k, v))
print()
print('"d" in m: {}'.format(('d' in m)))
La ricerca avviene sui singoli dizionari nell'ordine con il quale sono stati passati al costruttore, quindi il valore riportato per la chiave 'c
' proviene dal dizionario a
.
$ python3 collections_chainmap_read.py Valori individuali a = A b = B c = C Chiavi = ['c', 'b', 'a'] Valori = ['C', 'B', 'A'] Elementi: c = C b = B a = A "d" in m: False
Riordinare
ChainMap conserva la lista delle mappature sulle quali esegue le ricerche in una lista nel suo attributo maps
. La lista è modificabile, quindi è possibile aggiungere direttamente nuove mappature oppure modificare l'ordine degli elementi per controllare la ricerca ed aggiornare il comportamento.
# collections_chainmap_reorder.py
import collections
a = {'a': 'A', 'c': 'C'}
b = {'b': 'B', 'c': 'D'}
m = collections.ChainMap(a, b)
print(m.maps)
print('c = {}\n'.format(m['c']))
# inverte la lista
m.maps = list(reversed(m.maps))
print(m.maps)
print('c = {}'.format(m['c']))
Quando l'ordine nella lista delle mappature viene invertito, il valore associato a 'c
' cambia.
$ python3 collections_chainmap_reorder.py [{'c': 'C', 'a': 'A'}, {'c': 'D', 'b': 'B'}] c = C [{'c': 'D', 'b': 'B'}, {'c': 'C', 'a': 'A'}] c = D
Aggiornare Valori
Un ChainMap
non effettua una cache dei valori di mappatura dei dizionari, quindi la modifica del loro contenuto si riflette sui risultati quando si accede a ChainMap
.
# collections_chainmap_update_behind.py
import collections
a = {'a': 'A', 'c': 'C'}
b = {'b': 'B', 'c': 'D'}
m = collections.ChainMap(a, b)
print('Prima: {}'.format(m['c']))
a['c'] = 'E'
print('Dopo : {}'.format(m['c']))
La modifica dei valori associati a chiavi esistenti e l'aggiunta di nuovi elementi funziona allo stesso modo.
$ python3 collections_chainmap_update_behind.py Prima: C Dopo : E
E' anche possibile impostare direttamente i valori tramite ChainMap
, sebbene solo la prima mappatura nella catena è realmente modificata.
# collections_chainmap_update_directly.py
import collections
a = {'a': 'A', 'c': 'C'}
b = {'b': 'B', 'c': 'D'}
m = collections.ChainMap(a, b)
print('Prima:', m)
m['c'] = 'E'
print('Dopo :', m)
print('a:', a)
Quando il nuovo valore viene conservato utilizzando m
, la mappatura di a
viene aggiornata.
$ python3 collections_chainmap_update_directly.py Prima: ChainMap({'a': 'A', 'c': 'C'}, {'c': 'D', 'b': 'B'}) Dopo : ChainMap({'a': 'A', 'c': 'E'}, {'c': 'D', 'b': 'B'}) a: {'a': 'A', 'c': 'E'}
ChainMap
fornisce un metodo di convenienza per la creazione di una nuova istanza con una mappatura supplementare all'inizio della lista in maps
per evitare di dover modificare le struttura dati esistenti sottostanti.
# collections_chainmap_new_child.py
import collections
a = {'a': 'A', 'c': 'C'}
b = {'b': 'B', 'c': 'D'}
m1 = collections.ChainMap(a, b)
m2 = m1.new_child()
print('m1 prima:', m1)
print('m2 prima:', m2)
m2['c'] = 'E'
print('m1 dopo:', m1)
print('m2 dopo:', m2)
Il comportamento tipico delle strutture di stack rende conveniente l'uso di istanze di ChainMap
come modelli o contesti di applicazione, visto che è facile aggiungere od aggiornare valori in una iterazione, poi scaricare le modifiche per l'iterazione successiva.
$ python3 collections_chainmap_new_child.py m1 prima: ChainMap({'c': 'C', 'a': 'A'}, {'c': 'D', 'b': 'B'}) m2 prima: ChainMap({}, {'c': 'C', 'a': 'A'}, {'c': 'D', 'b': 'B'}) m1 dopo: ChainMap({'c': 'C', 'a': 'A'}, {'c': 'D', 'b': 'B'}) m2 dopo: ChainMap({'c': 'E'}, {'c': 'C', 'a': 'A'}, {'c': 'D', 'b': 'B'})
Per situazioni dove il nuovo contesto è conosciuto o costruito in anticipo, è anche possibile passare una mappatura a new_child()
.
# collections_chainmap_new_child_explicit.py
import collections
a = {'a': 'A', 'c': 'C'}
b = {'b': 'B', 'c': 'D'}
c = {'c': 'E'}
m1 = collections.ChainMap(a, b)
m2 = m1.new_child(c)
print('m1["c"] = {}'.format(m1['c']))
print('m2["c"] = {}'.format(m2['c']))
Questo è l'equivalente di.
m2 = collections.ChainMap(c, *m1.maps)
e produce.
$ python3 collections_chainmap_new_child_explicit.py m1["c"] = C m2["c"] = E
Vedere anche:
- ChainMap
- La documentazione della libreria standard per questo modulo
- Note di Portabilità
- Note di portabilità per collections.