shelve - Conservazione Persistente di Oggetti

Scopo: Implementa la conservazione persistente per oggetti Python arbitrari che possono essere preservati usando una API tipo dizionario.

Il modulo shelve può essere usato come semplice opzione di conservazione di oggetti Python quando non è richiesto un database relazionale. L'accesso avviene tramite chiavi, proprio come un dizionario. I valori sono serializzati con pickle e scritti in un database creato e gestito da dbm.

Creare un Nuovo Shelf

Il modo più semplice di usare shelve è tramite la classe DbfilenameShelf. Usa dbm per conservare i dati. Questa classe può essere usata direttamente oppure chiamando shelve.open(). Si intende per shelf il nuovo file creato con questa tecnica (n.d.t.).

# shelve_create.py

import shelve

with shelve.open('test_shelf.db') as s:
    s['key1'] = {
        'int': 10,
        'float': 9.5,
        'string': 'Dati di esempio',
    }

Per accedere nuovamente ai dati, si apra lo shelf e lo si utilizzi come un dizionario.

# shelve_existing.py

import shelve

with shelve.open('test_shelf.db') as s:
    existing = s['key1']

print(existing)

L'esecuzione di entrambi gli script di esempio produce il seguente risultato:

$ python3 shelve_create.py
$ python3 shelve_existing.py

{'int': 10, 'float': 9.5, 'string': 'Dati di esempio'}

Il modulo dbm non supporta la scrittura contemporanea allo stesso database da parte di applicazioni multiple, ma supporta la concorrenza per client a sola lettura. Se un client non modificherà lo shelf, si passi a shelve l'argomento flag='r' per aprire il database in sola lettura.

# shelve_readonly.py

import dbm
import shelve

with shelve.open('test_shelf.db', flag='r') as s:
    print('Esistente:', s['key1'])
    try:
        s['key1'] = 'nuovo valore'
    except dbm.error as err:
        print('ERRORE: {}'.format(err))

Se il programma tenta di modificare il database mentre è aperto in sola lettura, viene generata una eccezione. Il tipo di eccezione dipende dal modulo di database selezionato da dbm quando viene creato il database.

$ python3 shelve_readonly.py

Esistente: {'int': 10, 'float': 9.5, 'string': 'Dati di esempio', 'nuovo_valore': 'questo non esisteva prima'}
ERRORE: Reader can't store

Riscrittura

shelve non tiene traccia di modifiche a oggetti volatili, nella modalità predefinita. Il che significa che se il contenuto di un elemento conservato nello shelf è cambiato, occorre eseguire esplicitamente l'aggiornamento persistendo nuovamente l'intero elemento.

# shelve_withoutwriteback.py

import shelve

with shelve.open('test_shelf.db') as s:
    print(s['key1'])
    s['key1']['nuovo_valore'] = 'questo non esisteva prima'

with shelve.open('test_shelf.db', writeback=True) as s:
    print(s['key1'])

In questo esempio il dizionario a key1 non viene nuovamente conservato; quando lo shelf verrà nuovamente aperto, le modifiche non saranno conservate.

$ python3 shelve_create.py
$ python3 shelve_withoutwriteback.py

{'int': 10, 'float': 9.5, 'string': 'Dati di esempio'}
{'int': 10, 'float': 9.5, 'string': 'Dati di esempio'}

Per catturare automaticamente modifiche a oggetti volatili conservati nello shelf, si apra il database abilitando la riscrittura. Il flag writeback fa sì che tutti gli oggetti recuperati dal database vengano memorizzati usando una cache in memoria. Ciascun oggetto in cache viene riscritto nel database quando lo shelf viene chiuso.

# shelve_writeback.py

import shelve
import pprint

with shelve.open('test_shelf.db', writeback=True) as s:
    print('Dati iniziali:')
    pprint.pprint(s['key1'])

    s['key1']['nuovo_valore'] = 'questo non esisteva prima'

    print('\nModificato:')
    pprint.pprint(s['key1'])

with shelve.open('test_shelf.db', writeback=True) as s:
    print('\nPreservato:')
    pprint.pprint(s['key1'])

Sebbene vengano ridotte le possibilità di errore da parte del programmatore, e venga resa la persistenza dell'oggetto più trasparente, l'utilizzo della modalità di riscrittura potrebbe non essere quanto desiderato in ogni occasione. La cache consuma memoria supplememtare mentre lo shelf è aperto, e le interruzioni causate dalla riscrittura nel database di ogni oggetto conservato nella cache rallentano l'applicazione. Vengono riscritti nel database tutti gli oggetti in cache in quanto non vi è modo di sapere quale di essi è stato modificato. Se l'applicazione legge più dati di quanti ne scrive, la riscrittura avrà un impatto non nencessario sulle prestazioni.

$ python3 shelve_create.py
$ python3 shelve_writeback.py

Dati iniziali:
{'float': 9.5, 'int': 10, 'string': 'Dati di esempio'}

Modificato:
{'float': 9.5,
 'int': 10,
 'nuovo_valore': 'questo non esisteva prima',
 'string': 'Dati di esempio'}

Preservato:
{'float': 9.5,
 'int': 10,
 'nuovo_valore': 'questo non esisteva prima',
 'string': 'Dati di esempio'}

Tipi di Shelf Specifici

Gli esempi precedenti usano tutti l'implementazione predefinita. Usando shelve.open() in luogo della diretta implementazione è un modello di uso comune, specialmente se non importa quale tipo di database sia usato per la conservazione dei dati. A volte, tuttavia, quando il formato del database è importante, si utilizzi DbfilenameShelf oppure BsdDbShelf direttamente, e financo si subclassi Shelf per una soluzione personalizzata.

Vedere anche:

shelve
La documentazione della libreria standard per questo modulo.
dbm
Il modulo dbm trova una libreria DBM disponibile per creare un nuovo database.
feedcache
Il modulo feedcache usa shelve come opzione di conservazione predefinita.
shove
shove implementa una API simile ma con più formati di back-end