Konwertuj dict Pythona na ciąg znaków i odwrotnie

275

Piszę program, który przechowuje dane w obiekcie słownika, ale dane te muszą zostać zapisane w pewnym momencie podczas wykonywania programu i ponownie załadowane do obiektu słownika po ponownym uruchomieniu programu. Jak przekonwertować obiekt słownika na ciąg, który można zapisać do pliku i załadować z powrotem do obiektu słownika? Mamy nadzieję, że będzie to wspierać słowniki zawierające słowniki.

AJ00200
źródło

Odpowiedzi:

274

Moduł json jest tutaj dobrym rozwiązaniem. Ma tę przewagę nad ogórkiem, że generuje tylko zwykły tekst, i jest wieloplatformowy i między wersjami.

import json
json.dumps(dict)
Tyler Eaves
źródło
2
Zajmę się również tym modułem. Zarówno json, jak i marynata wydają się dość łatwe w użyciu, więc sprowadzą się do takich rzeczy, jak obsługa wielu platform. Dzięki
AJ00200,
5
W tym momencie marynata jest raczej przestarzała. Zawsze używam jsona do takich rzeczy. Bycie (względnie) czytelnym dla człowieka jest DUŻE i przez większość czasu.
Tyler Eaves,
30
Powinieneś dodać prosty przykład, aby użytkownicy mogli zobaczyć, jak to zrobić.
Miguel Vazq,
1
@TylerEaves Czy możesz podać przykład, jak należy to zrobić.
Boban
1
: czoło: nie zapomnij tak import jsonjak ja!
Jesse Chisholm
207

Jeśli twój słownik nie jest zbyt duży, być może str + eval może wykonać tę pracę:

dict1 = {'one':1, 'two':2, 'three': {'three.1': 3.1, 'three.2': 3.2 }}
str1 = str(dict1)

dict2 = eval(str1)

print dict1==dict2

Możesz użyć ast.literal_eval zamiast eval dla dodatkowego bezpieczeństwa, jeśli źródło jest niezaufane.

PabloG
źródło
13
Nie jestem tak naprawdę przygotowany do radzenia sobie z możliwymi exploitami, które mogłyby wprowadzić do kodu. Nie wiem, jakie problemy mogą mieć json lub marynata, ale wiem, że w tym przypadku eval byłby niebezpieczny.
AJ00200
5
@ AJ00200: i ast.literal_eval alternatywa, o której wspomniałem ?. Z pomocy Pythona: „Bezpiecznie oceniaj węzeł wyrażenia lub ciąg zawierający wyrażenie Python. Podany ciąg lub węzeł może składać się tylko z następujących struktur literału Python: ciągi, liczby, krotki, listy, dyktaty, logiczne i Brak. To może być używany do bezpiecznej oceny ciągów zawierających wyrażenia Pythona z niezaufanych źródeł bez konieczności samodzielnego analizowania wartości. ”
PabloG
Wydaje się to przydatne, ale kiedy poprzednio korzystałem z SQLite do obsługi tych danych i miał on ponad 1500 wpisów, więc jest dość duży i cały czas rośnie.
AJ00200,
164

Używam json:

import json

# convert to string
input = json.dumps({'id': id })

# load to dict
my_dict = json.loads(input) 
Eyal Ch
źródło
14

Użyj picklemodułu, aby zapisać go na dysku i załadować później.

ismail
źródło
2
@extraneon W rzeczywistości jest to odpowiedź na pytanie. Konwertuje go gdzieś na ciąg i zapisuje w pliku. Nie muszę robić faktycznej konwersji ani zapisywania plików, ponieważ wszystko jest zawarte w zalewie.
AJ00200
11

Dlaczego nie skorzystać z wbudowanej funkcji biblioteki Python 3 ast literal_eval . Lepiej jest używać literal_eval zamiast eval

import ast
str_of_dict = "{'key1': 'key1value', 'key2': 'key2value'}"
ast.literal_eval(str_of_dict)

da wynik jako rzeczywisty słownik

{'key1': 'key1value', 'key2': 'key2value'}

A jeśli poprosisz o konwersję słownika na ciąg, to co powiesz na użycie metody str () Pythona.

Załóżmy, że słownik to:

my_dict = {'key1': 'key1value', 'key2': 'key2value'}

I będzie to następująco:

str(my_dict)

Wydrukuje:

"{'key1': 'key1value', 'key2': 'key2value'}"

To takie proste, jak chcesz.

FightWithCode
źródło
5

Jeśli w Chinses

import codecs
fout = codecs.open("xxx.json", "w", "utf-8")
dict_to_json = json.dumps({'text':"中文"},ensure_ascii=False,indent=2)
fout.write(dict_to_json + '\n')
beta
źródło
1
To byłaby lepsza odpowiedź, gdybyś wyjaśnił, w jaki sposób podany kod odpowiada na pytanie.
pppery
4

Konwertuj słownik na JSON (ciąg)

import json 

mydict = { "name" : "Don", 
          "surname" : "Mandol", 
          "age" : 43} 

result = json.dumps(mydict)

print(result[0:20])

dostanie cię:

{„name”: „Don”, „sur

Konwertuj ciąg na słownik

back_to_mydict = json.loads(result) 
Harvey
źródło
3

Myślę, że powinieneś rozważyć użycie shelve modułu, który zapewnia trwałe, podobne do słownika obiekty podobne do plików. Jest łatwy w użyciu zamiast „prawdziwego” słownika, ponieważ prawie transparentnie zapewnia Twojemu programowi coś, czego można używać podobnie jak słownik, bez potrzeby jawnej konwersji go na ciąg znaków, a następnie zapisania go w pliku (lub odwrotnie versa).

Główną różnicą jest open()to, close()że musisz to zrobić na początku przed pierwszym użyciem, a potem , gdy skończysz (i być może w sync()zależności odwriteback użytej opcji). Wszelkie tworzone obiekty plików „półki” mogą zawierać zwykłe słowniki jako wartości, co pozwala na ich logiczne zagnieżdżenie.

Oto prosty przykład:

import shelve

shelf = shelve.open('mydata')  # open for reading and writing, creating if nec
shelf.update({'one':1, 'two':2, 'three': {'three.1': 3.1, 'three.2': 3.2 }})
shelf.close()

shelf = shelve.open('mydata')
print shelf
shelf.close()

Wynik:

{'three': {'three.1': 3.1, 'three.2': 3.2}, 'two': 2, 'one': 1}
martineau
źródło
2

Jeśli zależy Ci na prędkości, skorzystaj z ujson (UltraJSON), który ma takie samo API jak json:

import ujson
ujson.dumps([{"key": "value"}, 81, True])
# '[{"key":"value"},81,true]'
ujson.loads("""[{"key": "value"}, 81, true]""")
# [{u'key': u'value'}, 81, True]
Tomasz Bartkowiak
źródło
1

Używam do tego yaml, jeśli musi być czytelny (ani JSON, ani XML nie są tym IMHO), lub jeśli odczyt nie jest konieczny, używam marynaty.

pisać

from pickle import dumps, loads
x = dict(a=1, b=2)
y = dict(c = x, z=3)
res = dumps(y)
open('/var/tmp/dump.txt', 'w').write(res)

Przeczytaj ponownie

from pickle import dumps, loads
rev = loads(open('/var/tmp/dump.txt').read())
print rev
Gerard
źródło
Naprawdę powinieneś użyć bflagi podczas otwierania pliku tutaj.
Piotr Dobrogost
1
Mógłbym być bardziej wyraźny. Jednak dumps()domyślnie jest to protokół 0, który jest protokołem ascii. Dlatego 'rb'nie jest konieczne IMHO.
Gerard