web-dev-qa-db-fra.com

Comment sérialiser un dictionnaire Python dans une chaîne, puis revenir à un dictionnaire?)

Comment sérialiser un dictionnaire Python dans une chaîne, puis revenir à un dictionnaire? Le dictionnaire contient des listes et d'autres dictionnaires.

59
TIMEX

Cela dépend de ce que vous voulez utiliser. Si vous essayez simplement de le sauvegarder, vous devriez utiliser pickle (ou, si vous utilisez CPython 2.x, cPickle , ce qui est plus rapide).

>>> import pickle
>>> pickle.dumps({'foo': 'bar'})
b'\x80\x03}q\x00X\x03\x00\x00\x00fooq\x01X\x03\x00\x00\x00barq\x02s.'
>>> pickle.loads(_)
{'foo': 'bar'}

Si vous voulez que ce soit lisible, vous pouvez utiliser json :

>>> import json
>>> json.dumps({'foo': 'bar'})
'{"foo": "bar"}'
>>> json.loads(_)
{'foo': 'bar'}

json est cependant très limité dans ce qu’il supportera, alors que pickle peut être utilisé pour des objets arbitraires (si cela ne fonctionne pas automatiquement, la classe peut définir __getstate__ pour spécifier avec précision comment il doit être décapé.

>>> pickle.dumps(object())
b'\x80\x03cbuiltins\nobject\nq\x00)\x81q\x01.'
>>> json.dumps(object())
Traceback (most recent call last):
  ...
TypeError: <object object at 0x7fa0348230c0> is not JSON serializable
96
Chris Morgan

Utilisez le module json de Python ou simplejson si vous n'avez pas python 2.6 ou supérieur.

11
Dan D.

Pickle est bon mais je pense que ça vaut la peine de mentionner literal_eval du module ast pour une solution encore plus légère si vous ne sérialisez que les types de base python. C'est en principe une version "sûre" de la notoire eval fonction qui permet uniquement d’évaluer les types python de base) par opposition à tout code python valide.

Exemple:

>>> d = {}
>>> d[0] = range(10)
>>> d['1'] = {}
>>> d['1'][0] = range(10)
>>> d['1'][1] = 'hello'
>>> data_string = str(d)
>>> print data_string
{0: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], '1': {0: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 1: 'hello'}}

>>> from ast import literal_eval
>>> d == literal_eval(data_string)
True

Un avantage est que les données sérialisées sont juste python code, il est donc très convivial. Comparez-le à ce que vous obtiendrez avec pickle.dumps:

>>> import pickle
>>> print pickle.dumps(d)
(dp0
I0
(lp1
I0
aI1
aI2
aI3
aI4
aI5
aI6
aI7
aI8
aI9
asS'1'
p2
(dp3
I0
(lp4
I0
aI1
aI2
aI3
aI4
aI5
aI6
aI7
aI8
aI9
asI1
S'hello'
p5
ss.

L'inconvénient est que dès que les données incluent un type qui n'est pas supporté par literal_ast vous devrez passer à autre chose que le décapage.

10
Graphics Noob

Si vous faites entièrement confiance à la chaîne et ne vous souciez pas de attaques par injection de python , alors c'est une solution très simple:

d = { 'method' : "eval", 'safe' : False, 'guarantees' : None }
s = str(d)
d2 = eval(s)
for k in d2:
    print k+"="+d2[k]

Si vous êtes plus conscient de la sécurité alors ast.literal_eval est un meilleur pari.

10
yoyo

Une chose que json ne peut pas faire est de dict indexé avec des nombres. L'extrait suivant

import json
dictionary = dict({0:0, 1:5, 2:10})
serialized = json.dumps(dictionary)
unpacked   = json.loads(serialized)
print unpacked[0]

va jeter

KeyError: 0

Parce que les clés sont converties en chaînes. cPickle conserve le type numérique et le dict décompressé peut être utilisé immédiatement.

4
Przemek D

pyyaml ​​ devrait également être mentionné ici. Il est à la fois lisible par l'homme et peut sérialiser n'importe quel objet python.
pyyaml ​​est hébergé ici:
https://bitbucket.org/xi/pyyaml

1
georg

Bien que n'étant pas strictement sérialisation, json peut être une approche raisonnable ici. Cela permettra de gérer les listes et les dicts imbriqués, ainsi que les données, tant que vos données sont "simples": chaînes et types numériques de base.

1
Tyler Eaves