shelve – Stockage persistant d'objects Python arbitraires

Objectif : Le module shelve propose une infrastructure de stockage par une API similaire aux dictionnaires d'objets Python arbitraire pouvant être "picklés''.

Le module shelve peut être utilisé comme une alternative simple à une base de donnée, parfois trop complexe pour certains usages, pour le stockage persistant d'objets Python. Cette étagère [NdT: "shelve" en anglais] est accessible par des clés, exactement comme un dictionnaire. Les valeurs sont "picklée" et écrites dans une base de donnée crée et gérée par anydbm.

NdT : Dans les versions de Python ultérieures à la 3.0 le module anydbm a été renommé dbm, il convient donc de remplacer dans le texte ci-après toutes les références à anydbm par dbm. Le script 2to3 prend en charge automatiquement cette conversion.

Création d'une nouvelle étagère

La manière la plus simple d'utiliser shelve est de la faire à travers la classe DbfilenameShelf. Cette classe utilise anydbm pour stocker les données. Il est possible d'utiliser la classe directement ou d'appeler la fonction shelves.open() :

import shelve

s = shelve.open('test_shelf.db')
try:
    s['key1'] = { 'int': 10, 'float':9.5, 'string':'Sample data' }
finally:
    s.close()

Pour accéder aux données, il suffit d'ouvrir l'étagère et de l'utiliser comme un dictionnaire :

import shelve

s = shelve.open('test_shelf.db')
try:
    existing = s['key1']
finally:
    s.close()

print existing

Ces deux scripts exécutés l'un après l'autre devraient produire cette sortie :

$ python shelve_create.py
$ python shelve_existing.py
{'int': 10, 'float': 9.5, 'string': 'Sample data'}

Le module dbm ne supporte pas les accès concurrents de multiples applications essayant d'écrire dans la même base de données en même temps. Si vous savez que votre script client n'écrira pas dans l'étagère, il est possible de l'ouvrir en mode lecture seule.

import shelve

s = shelve.open('test_shelf.db', flag='r')
try:
    existing = s['key1']
finally:
    s.close()

print existing

Si votre programme essaye de modifier l'étagère alors qu'elle a été ouverte en mode lecture seule, une exception est levée. Le type de l'exception dépend du module de base de données choisi par anydbm au moment de la création de la base.

Ré-écriture

shelve ne suit pas, par défaut, les modifications des objets. Cela signifie que si vous altérez un objet stocké dans l'étagère, vous devrez explicitement le mettre à jour en y écrivant l'objet à nouveau.

import shelve

s = shelve.open('test_shelf.db')
try:
    print s['key1']
    s['key1']['new_value'] = 'this was not here before'
finally:
    s.close()

s = shelve.open('test_shelf.db', writeback=True)
try:
    print s['key1']
finally:
    s.close()

Dans cet exemple, la clé 'key1' du dictionnaire n'est pas ré-écrite. Ainsi, à la réouverture de l'étagère, on constate que les changements effectués n'ont pas été conservés :

$ python shelve_create.py
$ python shelve_withoutwriteback.py
{'int': 10, 'float': 9.5, 'string': 'Sample data'}
{'int': 10, 'float': 9.5, 'string': 'Sample data'}

Pour suivre automatiquement les modifications des objets stockés dans une étagère, il faut l'ouvrir avec la ré-écriture NdT: ''writeback'' activée. Le drapeau de ré-écriture indique à l'étagère de se souvenir de chaque objet extrait de l'étagère. Ceci est fait grâce à une mémoire cache. Chaque objet de la mémoire cache et également ré-écrit dans la base de donnée au moment de la fermeture de l'étagère.

import shelve

s = shelve.open('test_shelf.db', writeback=True)
try:
    print s['key1']
    s['key1']['new_value'] = 'this was not here before'
    print s['key1']
finally:
    s.close()

s = shelve.open('test_shelf.db', writeback=True)
try:
    print s['key1']
finally:
    s.close()

Bien que cela puisse permettre d'éviter au développeur certaines erreurs et que cela rende le stockage persistant d'objet plus transparent, l'utilisation de writeback n'est pas souhaitable dans toutes les situations. La consommation de mémoire supplémentaire induite par la mise en cache des objets à l'ouverture ainsi que le délai lié à l'écriture des objets de la mémoires cache à la fermeture peuvent être des désavantages. Comme il n'y a aucun moyen de vérifier l'état des objets de la mémoire cache, ils sont tous ré-écrits. Si votre application lit beaucoup plus d'objets qu'elle n'en écrit, la ré-écriture pourrait ajouter une charge supplémentaire importante.

$ python shelve_create.py
$ python shelve_writeback.py
{'int': 10, 'float': 9.5, 'string': 'Sample data'}
{'int': 10, 'new_value': 'this was not here before', 'float': 9.5, 'string': 'Sample data'}
{'int': 10, 'new_value': 'this was not here before', 'float': 9.5, 'string': 'Sample data'}

Étagères de types spécifiques

Les exemples précédents utilisent l'implémentation par défaut. L'utilisation de shelve.open() au lieu d'appeler directement l'une des implémentation de shelve est une cas d'usage typique quand la base de données utilisée pour stocker les objets est indifférente. Parfois cependant il peut être nécessaire de choisir une base de données spécifique. Dans ces situations il est possible d'appeler DbfilenameShelf ou BsdDbShelf directement, voir même une classe personnalisée dérivée Shelf.

Voir aussi

shelve

   La documentation officielle pour ce module.

anydbm

   Le module anydbm.

feedcache

   le module feedcache utilise shelve comme stockage par défaut.

shove

   shove implémente une API similaire mais propose plus de choix différent pour le stockage.

PyMOTW : shelve

   La version originale de ce PyMOTW.