Comment sérialiser un dictionnaire Python dans une chaîne, puis revenir à un dictionnaire? Le dictionnaire contient des listes et d'autres dictionnaires.
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
Utilisez le module json de Python ou simplejson si vous n'avez pas python 2.6 ou supérieur.
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.
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.
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.
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
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.