Przechowywanie słowników Python

198

Jestem przyzwyczajony do wprowadzania i wyprowadzania danych z Pythona za pomocą plików .csv, ale są oczywiste wyzwania. Wszelkie porady na temat prostych sposobów przechowywania słownika (lub zestawów słowników) w pliku json lub pck? Na przykład:

data = {}
data ['key1'] = "keyinfo"
data ['key2'] = "keyinfo2"

Chciałbym wiedzieć, jak to zapisać, a następnie jak go ponownie załadować.

mikrofon
źródło
8
Czy przeczytałeś dokumentację dotyczącą standardowych modułów json lub marynowanych ?
Greg Hewgill

Odpowiedzi:

443

Zapisz marynowane :

try:
    import cPickle as pickle
except ImportError:  # python 3.x
    import pickle

with open('data.p', 'wb') as fp:
    pickle.dump(data, fp, protocol=pickle.HIGHEST_PROTOCOL)

Zobacz dokumentację modułu ogórkowy dodatkowych informacji odnośnie protocolargumentu.

Ładunek marynowany :

with open('data.p', 'rb') as fp:
    data = pickle.load(fp)

JSON zapisz:

import json

with open('data.json', 'w') as fp:
    json.dump(data, fp)

Podaj dodatkowe argumenty, takie jak sort_keyslub, indentaby uzyskać ładny wynik. Argument sort_keys posortuje klucze alfabetycznie, a wcięcie spowoduje wcięcie struktury danych indent=Nspacjami.

json.dump(data, fp, sort_keys=True, indent=4)

Obciążenie JSON :

with open('data.json', 'r') as fp:
    data = json.load(fp)
Marty
źródło
4
JSON robi słowniki natywnie (chociaż oczywiście nie zachowują się dokładnie tak, jak słownik Pythona w pamięci, dla celów trwałości są identyczne). W rzeczywistości podstawową jednostką w json jest „Object”, który jest zdefiniowany jako {<ciąg>: <wartość>}. Wygląda podobnie? Moduł json w standardowej bibliotece obsługuje wszystkie rodzime typy języka Python i można go łatwo rozszerzyć przy minimalnej znajomości języka json w celu obsługi klas zdefiniowanych przez użytkownika. Strona główna JSON całkowicie definiuje język na nieco ponad 3 wydrukowanych stronach, dzięki czemu łatwo jest go szybko przyswoić / przetrawić.
Jonathanb
1
Warto też wiedzieć o trzecim argumencie pickle.dump. Jeśli plik nie musi być czytelny dla człowieka, może to znacznie przyspieszyć.
Steve Jessop
11
Jeśli dodasz klucze sort_keys i argumenty wcięcia do wywołania zrzutu, uzyskasz ładniejszy wynik. np json.dump(data, fp, sort_keys=True, indent=4). : Więcej informacji można znaleźć tutaj
Juliusmh
1
Prawdopodobnie powinieneś użyćpickle.dump(data, fp, protocol=pickle.HIGHEST_PROTOCOL)
Martin Thoma
1
W przypadku Pythona 3 użyjimport pickle
niebezpieczeństwo89
35

Minimalny przykład, pisanie bezpośrednio do pliku:

import json
json.dump(data, open(filename, 'wb'))
data = json.load(open(filename))

lub bezpieczne otwieranie / zamykanie:

import json
with open(filename, 'wb') as outfile:
    json.dump(data, outfile)
with open(filename) as infile:
    data = json.load(infile)

Jeśli chcesz zapisać go w ciągu zamiast w pliku:

import json
json_str = json.dumps(data)
data = json.loads(json_str)
agf
źródło
5

Aby zapisać do pliku:

import json
myfile.write(json.dumps(mydict))

Aby odczytać z pliku:

import json
mydict = json.loads(myfile.read())

myfile jest obiektem dla pliku, w którym zapisałeś dykt.

Rafe Kettler
źródło
czy masz json, który bierze pliki jako argument i pisze bezpośrednio do nich?
json.dump(myfile)ijson.load(myfile)
Niklas R
5

Jeśli szukasz serializacji, ale nie potrzebujesz danych w innych programach, zdecydowanie polecam shelvemoduł. Pomyśl o tym jak o trwałym słowniku.

myData = shelve.open('/path/to/file')

# check for values.
keyVar in myData

# set values
myData[anotherKey] = someValue

# save the data for future use.
myData.close()
gddc
źródło
2
jsonBardziej wygodne jest przechowywanie całego nagrania lub wczytanie całego nagrania . shelvejest lepszy tylko w przypadku uzyskiwania dostępu do jednego klucza na raz.
agf
3

Jeśli chcesz alternatywę dla picklelub json, możesz użyć klepto.

>>> init = {'y': 2, 'x': 1, 'z': 3}
>>> import klepto
>>> cache = klepto.archives.file_archive('memo', init, serialized=False)
>>> cache        
{'y': 2, 'x': 1, 'z': 3}
>>>
>>> # dump dictionary to the file 'memo.py'
>>> cache.dump() 
>>> 
>>> # import from 'memo.py'
>>> from memo import memo
>>> print memo
{'y': 2, 'x': 1, 'z': 3}

Z klepto, gdybyś używał serialized=True, słownik byłby zapisany memo.pkljako słownik marynowany zamiast z czystym tekstem.

Możesz uzyskać kleptotutaj: https://github.com/uqfoundation/klepto

dilljest prawdopodobnie lepszym wyborem do marynowania niż picklesam, ponieważ dillmoże serializować prawie wszystko w Pythonie. kleptorównież można użyć dill.

Możesz uzyskać dilltutaj: https://github.com/uqfoundation/dill

Dodatkowe mumbo-jumbo w pierwszych kilku wierszach jest kleptomożliwe, ponieważ można je skonfigurować do przechowywania słowników w pliku, w kontekście katalogu lub w bazie danych SQL. Interfejs API jest taki sam dla wszystkiego, co wybierzesz jako archiwum zaplecza. Daje ci słownik do archiwizacji, z którym możesz korzystać loadi dumpwchodzić w interakcje z archiwum.

Mike McKerns
źródło
3

Jest to stary temat, ale dla kompletności powinniśmy dołączyć ConfigParser i configparser, które są częścią standardowej biblioteki odpowiednio w Pythonie 2 i 3. Moduł ten czyta i zapisuje do pliku config / ini i (przynajmniej w Pythonie 3) zachowuje się na wiele sposobów jak słownik. Ma tę dodatkową zaletę, że można przechowywać wiele słowników w osobnych sekcjach pliku config / ini i przywoływać je. Słodkie!

Przykład Python 2.7.x.

import ConfigParser

config = ConfigParser.ConfigParser()

dict1 = {'key1':'keyinfo', 'key2':'keyinfo2'}
dict2 = {'k1':'hot', 'k2':'cross', 'k3':'buns'}
dict3 = {'x':1, 'y':2, 'z':3}

# make each dictionary a separate section in config
config.add_section('dict1')
for key in dict1.keys():
    config.set('dict1', key, dict1[key])

config.add_section('dict2')
for key in dict2.keys():
    config.set('dict2', key, dict2[key])

config.add_section('dict3')
for key in dict3.keys():
    config.set('dict3', key, dict3[key])

# save config to file
f = open('config.ini', 'w')
config.write(f)
f.close()

# read config from file
config2 = ConfigParser.ConfigParser()
config2.read('config.ini')

dictA = {}
for item in config2.items('dict1'):
    dictA[item[0]] = item[1]

dictB = {}
for item in config2.items('dict2'):
    dictB[item[0]] = item[1]

dictC = {}
for item in config2.items('dict3'):
    dictC[item[0]] = item[1]

print(dictA)
print(dictB)
print(dictC)

Przykład Python 3.X.

import configparser

config = configparser.ConfigParser()

dict1 = {'key1':'keyinfo', 'key2':'keyinfo2'}
dict2 = {'k1':'hot', 'k2':'cross', 'k3':'buns'}
dict3 = {'x':1, 'y':2, 'z':3}

# make each dictionary a separate section in config
config['dict1'] = dict1
config['dict2'] = dict2
config['dict3'] = dict3

# save config to file
f = open('config.ini', 'w')
config.write(f)
f.close()

# read config from file
config2 = configparser.ConfigParser()
config2.read('config.ini')

# ConfigParser objects are a lot like dictionaries, but if you really
# want a dictionary you can ask it to convert a section to a dictionary
dictA = dict(config2['dict1'] )
dictB = dict(config2['dict2'] )
dictC = dict(config2['dict3'])

print(dictA)
print(dictB)
print(dictC)

wyjście konsoli

{'key2': 'keyinfo2', 'key1': 'keyinfo'}
{'k1': 'hot', 'k2': 'cross', 'k3': 'buns'}
{'z': '3', 'y': '2', 'x': '1'}

zawartość config.ini

[dict1]
key2 = keyinfo2
key1 = keyinfo

[dict2]
k1 = hot
k2 = cross
k3 = buns

[dict3]
z = 3
y = 2
x = 1
bfris
źródło
1

Jeśli zapisz w pliku json, najlepszym i najłatwiejszym sposobem na to jest:

import json
with open("file.json", "wb") as f:
    f.write(json.dumps(dict).encode("utf-8"))
Adam Liu
źródło
dlaczego jest to łatwiejsze niż json.dump( )przedstawione w drugiej odpowiedzi?
baxx
0

moim przypadkiem użycia było zapisanie wielu obiektów JSON w pliku, a odpowiedź Marty'ego nieco mi pomogła. Ale aby obsłużyć mój przypadek użycia, odpowiedź nie była kompletna, ponieważ zastąpiłaby stare dane za każdym razem, gdy zapisywany jest nowy wpis.

Aby zapisać wiele wpisów w pliku, należy sprawdzić starą zawartość (tzn. Przeczytać przed zapisem). Typowy plik zawierający dane JSON ma albo root, listalbo objectjako root. Uznałem więc, że mój plik json zawsze ma list of objectsi za każdym razem, gdy dodam do niego dane, najpierw ładuję listę, dołączam do niej moje nowe dane i zrzucam z powrotem do instancji file ( w) tylko do zapisu :

def saveJson(url,sc): #this function writes the 2 values to file
    newdata = {'url':url,'sc':sc}
    json_path = "db/file.json"

    old_list= []
    with open(json_path) as myfile:  #read the contents first
        old_list = json.load(myfile)
    old_list.append(newdata)

    with open(json_path,"w") as myfile:  #overwrite the whole content
        json.dump(old_list,myfile,sort_keys=True,indent=4)

    return "sucess"

nowy plik json będzie wyglądał mniej więcej tak:

[
    {
        "sc": "a11",
        "url": "www.google.com"
    },
    {
        "sc": "a12",
        "url": "www.google.com"
    },
    {
        "sc": "a13",
        "url": "www.google.com"
    }
]

UWAGA: Ważne jest, aby mieć plik o nazwie file.jsonz []jak wstępnych danych dla tego podejścia do pracy

PS: niezwiązane z pierwotnym pytaniem, ale to podejście można również ulepszyć, najpierw sprawdzając, czy nasz wpis już istnieje (na podstawie 1 / wielu kluczy), a dopiero potem dodając i zapisując dane. Daj mi znać, jeśli ktoś potrzebuje tej kontroli, dodam do odpowiedzi

ansh sachdeva
źródło