Jak zapisać słownik do pliku?

139

Mam problem ze zmianą wartości dykta i zapisaniem dyktu do pliku tekstowego (format musi być taki sam), chcę tylko zmienić member_phonepole.

Mój plik tekstowy ma następujący format:

memberID:member_name:member_email:member_phone

i podzieliłem plik tekstowy na:

mdict={}
for line in file:
    x=line.split(':')
    a=x[0]
    b=x[1]
    c=x[2]
    d=x[3]
    e=b+':'+c+':'+d

    mdict[a]=e

Kiedy próbuję zmienić member_phonezapisane w d, wartość zmieniła się nie płynie przez klawisz,

def change(mdict,b,c,d,e):
    a=input('ID')
    if a in mdict:
        d= str(input('phone'))
        mdict[a]=b+':'+c+':'+d
    else:
        print('not')

i jak zapisać dyktando do pliku tekstowego o tym samym formacie?

XueYuan Wang
źródło

Odpowiedzi:

258

Python ma moduł pikle tylko do tego typu rzeczy.

Te funkcje to wszystko, czego potrzebujesz do zapisywania i ładowania prawie każdego obiektu:

def save_obj(obj, name ):
    with open('obj/'+ name + '.pkl', 'wb') as f:
        pickle.dump(obj, f, pickle.HIGHEST_PROTOCOL)

def load_obj(name ):
    with open('obj/' + name + '.pkl', 'rb') as f:
        return pickle.load(f)

Te funkcje zakładają, że masz objfolder w bieżącym katalogu roboczym, który będzie używany do przechowywania obiektów.

Zauważ, że pickle.HIGHEST_PROTOCOLjest to format binarny, który nie zawsze może być wygodny, ale jest dobry dla wydajności. Protokół 0to format tekstowy.

W celu zapisywania kolekcji Pythona istnieje moduł półki .

Zah
źródło
1
save_objwydaje się, że plik obj/'+ name + '.pkljuż istnieje. Utworzyłem słownik o nazwie Q, zapełniłem go i save_obj(Q, "Qtable")wykonałem połączenie. Otrzymałem błąd: W FileNotFoundError: [Errno 2] No such file or directory: 'obj/Qtable.pkl'jaki sposób można utworzyć plik w pierwszej kolejności przed zapisaniem do niego?
Wykałaczka Anemone
1
@ToothpickAnemone użyj wb+do utworzenia pliku, tj .:with open('obj/'+ name + '.pkl', 'wb+')
andrey.s
1
@ andrey.s: Nie sądzę, żeby to, co mówisz, miało jakiekolwiek znaczenie, ponieważ nie rozwiązuje problemu.
martineau
1
@Toothpick Anemone: Dodanie a +do trybu nie wpłynie na twój problem (andrey.s jest niepoprawny). Wygląda na to, że Twój problem wynika z jednej lub dwóch rzeczy. Aby save_obj()w tej odpowiedzi działała, podkatalog o nazwie "obj"musi już istnieć, ponieważ open()nie utworzy go automatycznie. Drugi pierwszy argument save_obj()to obiekt Pythona, który ma zostać zapisany, a nie nazwa podkatalogu (chociaż nie jest do końca jasne, co masz na myśli przez wywołanie Qw przykładzie save_obj(Q, "Qtable")). Możesz utworzyć katalog, jeśli nie kończy się już z os.mkdir().
martineau
168

Pickle to prawdopodobnie najlepsza opcja, ale na wypadek, gdyby ktoś zastanawiał się, jak zapisać i załadować słownik do pliku za pomocą NumPy:

import numpy as np

# Save
dictionary = {'hello':'world'}
np.save('my_file.npy', dictionary) 

# Load
read_dictionary = np.load('my_file.npy',allow_pickle='TRUE').item()
print(read_dictionary['hello']) # displays "world"

FYI: przeglądarka plików NPY

Franck Dernoncourt
źródło
4
do czego służy .item ()?
Gulzar
Dlaczego ta odpowiedź jest mniej przychylna niż odpowiedź „pickle” @Zah? Bardziej złożona przestrzeń?
Nathan
1
Możliwość @frank, ponieważ pickle jest częścią standardowej biblioteki Pythona, gdzie numpy jest niezależnym projektem.
Maxim Veksler,
2
@Gulzar z tego, co sprawdziłem, np.load zwraca ndarray (robiąc to type(read_dictionary)ujawnia), a .item () w zasadzie konwertuje ten element na obiekt skalarny Pythona, który jest słownikiem, jak podano tutaj
abhyudayasrinet
2
@Shai czy zainstalowałeś pakiet numpy ...?
Eben
26

Z jsonmodułu możemy skorzystać również w przypadku, gdy słowniki lub inne dane można łatwo zmapować do formatu JSON .

import json

# Serialize data into file:
json.dump( data, open( "file_name.json", 'w' ) )

# Read data from file:
data = json.load( open( "file_name.json" ) )

Takie rozwiązanie przynosi wiele korzyści , m.in. prace dla Pythona 2.x oraz Python 3.x w niezmienionej formie , a ponadto, dane zapisane w JSON formacie mogą być łatwo przenoszone między wielu różnych platformach lub programów . Te dane są również czytelne dla człowieka .

simhumileco
źródło
Dobre podejście, ale nie sądzę, aby można było bezpiecznie używać go openbezpośrednio zamiast kontekstu utworzonego przez with. Czy istnieje gwarancja, że ​​uchwyt pliku zostanie zamknięty, jeśli się json.dumpnie powiedzie?
Dr_Zaszuś
18

Nie jestem pewien, jakie jest twoje pierwsze pytanie, ale jeśli chcesz zapisać słownik do pliku, skorzystaj z jsonbiblioteki. Przejrzyj dokumentację obciążeń i wstawiaj funkcje.

Jan
źródło
Dlaczego json? Jeszcze łatwiej jest po prostu zrzucić słownik Pythona do pliku za pomocą "repr"
mguijarr
5
@mguijarr, ale przetworzenie go z powrotem nie jest takie łatwe. Plus json można łatwo edytować ręcznie i importować do dowolnego innego programu.
kalhartt
1
Podoba mi się sugestia Johna - zobacz ten post, aby zobaczyć dobry i prosty przykład stackoverflow.com/a/11027021/765827
jacanterbury
9

Zapisz i wczytaj dykt do pliku:

def save_dict_to_file(dic):
    f = open('dict.txt','w')
    f.write(str(dic))
    f.close()

def load_dict_from_file():
    f = open('dict.txt','r')
    data=f.read()
    f.close()
    return eval(data)
junglejet
źródło
3

W przypadku słownika ciągów znaków, takiego jak ten, z którym masz do czynienia, można to zrobić przy użyciu tylko wbudowanych funkcji przetwarzania tekstu Pythona.

(Pamiętaj, że to nie zadziała, jeśli wartości są czymś innym).

with open('members.txt') as file:
    mdict={}
    for line in file:
        a, b, c, d = line.strip().split(':')
        mdict[a] = b + ':' + c + ':' + d

a = input('ID: ')
if a not in mdict:
    print('ID {} not found'.format(a))
else:
    b, c, d = mdict[a].split(':')
    d = input('phone: ')
    mdict[a] = b + ':' + c + ':' + d  # update entry
    with open('members.txt', 'w') as file:  # rewrite file
        for id, values in mdict.items():
            file.write(':'.join([id] + values.split(':')) + '\n')
martineau
źródło
To nie działa w przypadku słowników: file.write (':'. Join ([id] + values.split (':')) + '\ n') AttributeError: obiekt 'dict' nie ma atrybutu 'split'
Shai Alon
@ShaiAlon: Nie ze wszystkimi, nie. To na pewno nie pracować z tymi, których wartości są ciągami (które mają split()metody)-co jest tematem tej kwestii. Wygląda na to, że próbujesz użyć go w słowniku ze słownikami, więc nie, to nie zadziała. Nie doceniam również głosów negatywnych od ludzi, ponieważ tak naprawdę nie rozumieją pytania (a tym samym kontekstu udzielanych odpowiedzi). Zaktualizuję moją odpowiedź, aby udzielić, gdy jej użyję, więc cofnij swój głos negatywny.
martineau
3

Sugerowałbym zapisywanie danych w formacie JSON zamiast w formacie pikle, ponieważ pliki JSON są czytelne dla człowieka, co ułatwia debugowanie, ponieważ dane są małe. Pliki JSON są również używane przez inne programy do odczytu i zapisu danych. Więcej na ten temat przeczytasz tutaj

Musisz zainstalować moduł JSON, możesz to zrobić za pomocą pip:

pip install json


# To save the dictionary into a file:
json.dump( data, open( "myfile.json", 'w' ) )

Spowoduje to utworzenie pliku json o nazwie myfile.

# To read data from file:
data = json.load( open( "myfile.json" ) )

Odczytuje i zapisuje dane myfile.json w obiekcie danych.

Kavin Sabharwal
źródło
2

Chyba że naprawdę chcesz zachować słownik, myślę, że najlepszym rozwiązaniem jest użycie csvmodułu Python do odczytania pliku. Następnie otrzymujesz wiersze danych i możesz zmienić member_phonelub cokolwiek chcesz; wreszcie możesz użyćcsv modułu ponownie, aby zapisać plik w tym samym formacie, w jakim go otworzyłeś.

Kod do czytania:

import csv

with open("my_input_file.txt", "r") as f:
   reader = csv.reader(f, delimiter=":")
   lines = list(reader)

Kod do pisania:

with open("my_output_file.txt", "w") as f:
   writer = csv.writer(f, delimiter=":")
   writer.writerows(lines)

Oczywiście musisz dostosować swoją change()funkcję:

def change(lines):
    a = input('ID')
    for line in lines:
      if line[0] == a:
        d=str(input("phone"))
        line[3]=d
        break
    else:
      print "not"
mguijarr
źródło
co to znaczyOf course, you need to adapt your change() function:
kRazzy R
1
w pytaniu dict użyto a, podczas gdy csv działa bardziej jak lista
mguijarr
1

Nie mierzyłem tego w czasie, ale założę się, że h5 jest szybsze niż pikle; rozmiar pliku z kompresją jest prawie na pewno mniejszy.

import deepdish as dd
dd.io.save(filename, {'dict1': dict1, 'dict2': dict2}, compression=('blosc', 9))
słowa do rozumu
źródło
-2

Szybkie i brudne rozwiązanie: przekonwertuj dyktę na łańcuch i zapisz do pliku, np .:

#dict could be anything:

savedict = open('savedict001.txt', 'w')
savedict.write(str(dict))
savedict.close()
Patrick Stacey
źródło
Konwersja dict na str i zapisywanie nie działa, szczególnie gdy masz pd.Series lub np.ndarray jako klucze w łańcuchach.
Arpan Srivastava