Con Python, ¿puedo mantener un diccionario persistente y modificarlo?

Por lo tanto, quiero almacenar un diccionario en un archivo persistente. ¿Hay alguna forma de usar los métodos regulares del diccionario para agregar, imprimir o eliminar entradas del diccionario en ese archivo?

Parece que podría usar cPickle para almacenar el diccionario y cargarlo, pero no estoy seguro de a dónde llevarlo.

Si sus claves (no necesariamente los valores) son cadenas, el módulo estándar de la biblioteca de estanterías hace lo que usted desea de manera bastante perfecta.

Usar json

Similar a la respuesta de Pete, me gusta usar JSON porque se asigna muy bien a las estructuras de datos de Python y es muy legible:

La persistencia de datos es trivial:

>>> import json >>> db = {'hello': 123, 'foo': [1,2,3,4,5,6], 'bar': {'a': 0, 'b':9}} >>> fh = open("db.json", 'w') >>> json.dump(db, fh) 

y cargarlo es casi lo mismo:

 >>> import json >>> fh = open("db.json", 'r') >>> db = json.load(fh) >>> db {'hello': 123, 'bar': {'a': 0, 'b': 9}, 'foo': [1, 2, 3, 4, 5, 6]} >>> del new_db['foo'][3] >>> new_db['foo'] [1, 2, 3, 5, 6] 

Además, la carga de JSON no sufre los mismos problemas de seguridad que los que se shelve y los pickle , aunque el IIRC es más lento que el encurtido.

Si quieres escribir en cada operación:

Si desea guardar en cada operación, puede crear una subclase del objeto dict de Python:

 import os import json class DictPersistJSON(dict): def __init__(self, filename, *args, **kwargs): self.filename = filename self._load(); self.update(*args, **kwargs) def _load(self): if os.path.isfile(self.filename) and os.path.getsize(self.filename) > 0: with open(self.filename, 'r') as fh: self.update(json.load(fh)) def _dump(self): with open(self.filename, 'w') as fh: json.dump(self, fh) def __getitem__(self, key): return dict.__getitem__(self, key) def __setitem__(self, key, val): dict.__setitem__(self, key, val) self._dump() def __repr__(self): dictrepr = dict.__repr__(self) return '%s(%s)' % (type(self).__name__, dictrepr) def update(self, *args, **kwargs): for k, v in dict(*args, **kwargs).items(): self[k] = v self._dump() 

Que puedes usar así:

 db = DictPersistJSON("db.json") db["foo"] = "bar" # Will trigger a write 

Lo que es terriblemente ineficiente, pero puede despegar rápidamente.

¿Desea eliminar del archivo cuando se carga el progtwig, modificarlo como un diccionario normal en la memoria mientras el progtwig se está ejecutando, hacer un pickle en el archivo cuando el progtwig sale? No estoy seguro exactamente qué más estás pidiendo aquí.

Suponiendo que las claves y los valores tienen implementaciones de trabajo de repr , una solución es que guarde la representación de cadena del diccionario ( repr(dict) ) en el archivo. Puedes cargarlo usando la función eval(inputstring) ). Hay dos desventajas principales de esta técnica:

1) No funcionará con tipos que tienen una implementación inutilizable de repr (o incluso puede parecer que funciona, pero falla). Tendrá que prestar al menos un poco de atención a lo que está sucediendo.

2) Su mecanismo de carga de archivos es básicamente un código Python que se ejecuta de forma directa. No es bueno para la seguridad a menos que controle completamente la entrada.

Tiene 1 ventaja: absurdamente fácil de hacer.

Mi método favorito (que no usa las funciones estándar del diccionario de Python): Lee / escribe archivos YAML usando PyYaml . Vea esta respuesta para más detalles , resumidos aquí:

Crea un archivo YAML, “employment.yml”:

 new jersey: mercer county: pumbers: 3 programmers: 81 middlesex county: salesmen: 62 programmers: 81 new york: queens county: plumbers: 9 salesmen: 36 

Paso 3: Léelo en Python

 import yaml file_handle = open("employment.yml") my__dictionary = yaml.safe_load(file_handle) file_handle.close() 

y ahora my__dictionary tiene todos los valores. Si necesitaba hacer esto sobre la marcha, cree una cadena que contenga YAML y analícela con yaml.safe_load.

El decapado tiene una desventaja. puede ser costoso si su diccionario tiene que leerse y escribirse con frecuencia desde el disco y es grande. Pickle vuelca las cosas (entero). Unpickle obtiene las cosas (en general).

Si tienes que manejar pequeños dictados, pickle está bien. Si va a trabajar con algo más complejo, vaya por berkelydb. Básicamente está hecho para almacenar pares clave: valor.

Si usar solo cadenas como claves (según lo permitido por el módulo de archivado ) no es suficiente, FileDict podría ser una buena manera de resolver este problema.