Wie serialisiere ich ein Python-Wörterbuch in eine Zeichenfolge und dann zurück in ein Wörterbuch?

73

Wie serialisiere ich ein Python-Wörterbuch in eine Zeichenfolge und dann zurück in ein Wörterbuch? Das Wörterbuch enthält Listen und andere Wörterbücher.

TIMEX
quelle
Kennen Sie sich aus pickle?
Gabe
ein Modul, das Teil der Python Standard Library ist
Joachim Wagner

Antworten:

116

Es hängt davon ab, wofür Sie es verwenden möchten. Wenn Sie nur versuchen, es zu speichern, sollten Sie es verwenden pickle(oder, wenn Sie CPython 2.x verwenden cPickle, das schneller ist).

>>> 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'}

Wenn Sie möchten, dass es lesbar ist, können Sie Folgendes verwenden json:

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

jsonist jedoch sehr begrenzt in der Unterstützung, während picklees für beliebige Objekte verwendet werden kann (wenn es nicht automatisch funktioniert, kann die Klasse definieren __getstate__, um genau anzugeben, wie es eingelegt werden soll).

>>> 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
Chris Morgan
quelle
18
Ich wünschte, ich wüsste, wofür um alles in der Welt -1 ist.
Chris Morgan
7
Ich denke, diese -1 könnte dazu dienen, Sicherheitsprobleme beim Beizen nicht zu erwähnen. Siehe stackoverflow.com/questions/10282175/attacking-pythons-pickle
Piotr Dobrogost
Es ist erwähnenswert, dass der cPickle-Teil der Antwort für Python 3.x nicht relevant ist. Sehen Sie hier für die offizielle Erklärung. Kurz gesagt, die beschleunigte C-Version eines Pakets sollte die Standardauswahl für jedes Python-Modul sein, und falls nicht verfügbar, greift das Modul selbst auf die Python-Implementierung zurück. Dies kapselt die Implementierung vom Benutzer. Zitat:In Python 3.0... Users should always import the standard version, which attempts to import the accelerated version and falls back to the pure Python version.
Ori
" Warnung Das Pickle-Modul ist nicht sicher . Entpacken Sie nur Daten, denen Sie vertrauen." - docs
ArtuX
11

Verwenden Sie das json- Modul von Python oder simplejson, wenn Sie nicht über Python 2.6 oder höher verfügen.

Dan D.
quelle
3
+1: json ist viel besser als pickle und kann auf die gleiche Weise verwendet werden: json.dumps(mydict)undjson.loads(mystring)
nosklo
11
Aber json kann nur Strings, Zahlen, Listen und Wörterbücher erstellen, während pickle jeden Python-Typ ausführen kann, aber json ist weitaus portabler als pickle für die Typen, die es ausführen kann
Dan D.
Wenn Sie json.dumps()kümmern sich um einige Arten ( False, True, und None) , weil sie mit nicht kompatibel sindjson
Jason Heo
10

Wenn Sie der Zeichenfolge voll vertrauen und sich nicht für Python-Injektionsangriffe interessieren, ist dies eine sehr einfache Lösung:

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

Wenn Sie sicherheitsbewusster sind, ast.literal_evalist dies eine bessere Wahl.

yoyo
quelle
Ehrlich gesagt ist dies die Methode, die ich die ganze Zeit verwende. Vielen Dank für den Sicherheitstipp. Ich verwende repr anstelle von str, wenn das Wörterbuch benutzerdefinierte Objekte enthält, die durch den repr-String initialisiert werden können
Evan Pu
1
Sie sollten ast.literal_evalstandardmäßig verwenden. evalhat keine Mehrwert und ein großes Sicherheitsproblem.
Jean-François Fabre
Schlimme Dinge passieren, weil Personen ehrlich gesagt dachten, dass es in ihrem besonderen Code-Frieden keine Sicherheitsbedenken gibt, so dass sie einfach glücklich evalweg können. Ich bin jedes Mal nur angewidert, jemand fördert diese Kultur der Schlamperei. Verwenden Sie einfach json.dumpsund json.loads(oder eine andere Nichtlösung eval), es gibt keinen wirklichen Grund, dies nicht zu
tun
10

Pickle ist großartig, aber ich denke, es ist erwähnenswert, literal_evaldas astModul für eine noch leichtere Lösung zu erwähnen, wenn Sie nur grundlegende Python-Typen serialisieren. Es ist im Grunde eine "sichere" Version der berüchtigten evalFunktion, die nur die Bewertung grundlegender Python-Typen im Gegensatz zu einem gültigen Python-Code ermöglicht.

Beispiel:

>>> 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

Ein Vorteil ist, dass die serialisierten Daten nur Python-Code sind und daher sehr menschenfreundlich sind. Vergleichen Sie es mit dem, was Sie bekommen würden 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.

Der Nachteil ist, dass Sie, sobald die Daten einen Typ enthalten, der von nicht unterstützt wird literal_ast, zu etwas anderem wie Beizen übergehen müssen.

Grafik Noob
quelle
5

Eine Sache, jsondie nicht getan werden kann, ist die dictIndizierung mit Ziffern. Das folgende Snippet

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

wird werfen

KeyError: 0

Weil Schlüssel in Zeichenfolgen konvertiert werden. cPicklebehält den numerischen Typ bei und das entpackte dictkann sofort verwendet werden.

Przemek D.
quelle
1

Obwohl dies keine strikte Serialisierung ist, kann json hier ein vernünftiger Ansatz sein. Damit werden verschachtelte Dikte und Listen sowie Daten behandelt, solange Ihre Daten "einfach" sind: Zeichenfolgen und grundlegende numerische Typen.

Tyler Eaves
quelle
1

Pyyaml sollte auch hier erwähnt werden. Es ist sowohl für Menschen lesbar als auch kann jedes Python-Objekt serialisieren.
pyyaml ​​wird hier gehostet:
https://bitbucket.org/xi/pyyaml

georg
quelle
-2

Wenn Sie nur serialisieren möchten, ist pprint möglicherweise auch eine gute Option. Es erfordert die Serialisierung des Objekts und einen Dateistream.

Hier ist ein Code:

from pprint import pprint
my_dict = {1:'a',2:'b'}
with open('test_results.txt','wb') as f:
    pprint(my_dict,f)

Ich bin mir nicht sicher, ob wir leicht deserialisieren können. Ich habe json früher zum Serialisieren und Deserialisieren verwendet, was in den meisten Fällen korrekt funktioniert.

f.write(json.dumps(my_dict, sort_keys = True, indent = 2, ensure_ascii=True))

In einem bestimmten Fall gab es jedoch einige Fehler beim Schreiben von Nicht-Unicode-Daten in json.

smartexpert
quelle