Como salvar um dicionário em um arquivo?

139

Estou com problemas para alterar um valor do dict e salvá-lo em um arquivo de texto (o formato deve ser o mesmo), só quero alterar o member_phonecampo.

Meu arquivo de texto tem o seguinte formato:

memberID:member_name:member_email:member_phone

e eu divido o arquivo de texto com:

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

Quando tento alterar o member_phonearmazenado d, o valor mudou, não flui pela chave,

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

e como salvar o dict em um arquivo de texto com o mesmo formato?

XueYuan Wang
fonte

Respostas:

258

O Python possui o módulo pickle apenas para esse tipo de coisa.

Essas funções são tudo o que você precisa para salvar e carregar quase qualquer objeto:

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)

Essas funções assumem que você possui uma objpasta no seu diretório de trabalho atual, que será usado para armazenar os objetos.

Observe que pickle.HIGHEST_PROTOCOLé um formato binário, que nem sempre pode ser conveniente, mas é bom para o desempenho. Protocolo 0é um formato de texto.

Para salvar coleções de Python, existe o módulo shelve .

Zah
fonte
1
save_objparece exigir que o arquivo obj/'+ name + '.pkljá exista. Criei um dicionário chamado Q, preenchi-o e fiz a ligação save_obj(Q, "Qtable"). Recebi um erro: FileNotFoundError: [Errno 2] No such file or directory: 'obj/Qtable.pkl'como criar o arquivo antes de escrever nele?
Palito Anêmona
1
@ToothpickAnemone use wb+to create file, ie:with open('obj/'+ name + '.pkl', 'wb+')
andrey.s 4/17
1
@ andrey.s: Eu não acho que o que você diz fará alguma diferença porque não soluciona o problema.
martineau
1
@ Palito Anêmona: Adicionar um +ao modo não afetará o seu problema (o andrey.s está incorreto). Seu problema parece ser por causa de uma ou duas coisas. Para que save_obj()esta resposta funcione, um subdiretório nomeado "obj" deve existir, porque open()não o criará automaticamente. Segundo, o primeiro argumento save_obj()é o objeto Python a ser salvo, não o nome do subdiretório (embora não esteja totalmente claro o que você quis dizer com Qna save_obj(Q, "Qtable")chamada de exemplo ). Você pode criar um diretório se ele ainda não sair os.mkdir().
martineau
168

Pickle é provavelmente a melhor opção, mas caso alguém se pergunte como salvar e carregar um dicionário em um arquivo usando o 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"

Visualizador de arquivos FYI: NPY

Franck Dernoncourt
fonte
4
para que serve o item ()?
Gulzar
Por que esta resposta é menos votada do que a resposta "pickle" de @Zah? Mais complexo espacial?
Nathan
1
@frank possibilidade porque pickle faz parte da biblioteca padrão do python, onde numpy é um projeto independente.
Maxim Veksler
2
@Gulzar do que eu olhei para cima, np.load retornos uma ndarray (fazendo um type(read_dictionary)revela assim) e .item () basicamente converte esse elemento para um objeto de python escalar que é um dicionário como afirmado aqui
abhyudayasrinet
2
@Shai você instalou o pacote numpy ...?
Eben
26

Também podemos usar o jsonmódulo no caso em que dicionários ou outros dados podem ser facilmente mapeados para o formato 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" ) )

Esta solução traz muitos benefícios , por exemplo, obras para Python 2.x e Python 3.x em uma forma inalterada e, além disso, dados guardados no JSON formato pode ser facilmente transferidos entre muitas plataformas ou programas diferentes . Esses dados também são legíveis por humanos .

simhumileco
fonte
Boa abordagem, mas não acho seguro usá-lo opendiretamente, em vez de um contexto criado por with. Existe uma garantia, o identificador do arquivo será fechado se json.dumpfalhar?
Dr_Zaszuś
18

Não tenho certeza de qual é sua primeira pergunta, mas se você deseja salvar um dicionário em um arquivo, use a jsonbiblioteca. Procure a documentação das cargas e coloca funções.

John
fonte
Por que json? É ainda mais fácil de simplesmente despejar o dicionário Python para um arquivo usando "repr"
mguijarr
5
@mguijarr, mas analisá-lo de volta não é tão fácil. Além disso, o json é fácil de editar manualmente e importar para qualquer outro programa.
Kalhartt 5/10
1
I como a sugestão de John - veja este post para um bom e simples exemplo stackoverflow.com/a/11027021/765827
jacanterbury
9

Salve e carregue o comando no arquivo:

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

Para um dicionário de strings como o que você está lidando, isso pode ser feito usando apenas os recursos internos de processamento de texto do Python.

(Observe que isso não funcionaria se os valores fossem outra coisa.)

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
fonte
Isso não funciona nos dicionários: file.write (':'. Join ([id] + values.split (':')) + '\ n') AttributeError: o objeto 'dict' não tem atributo 'split'
Shai Alon
@ShaiAlon: Não com todos eles, não. Ele definitivamente faz o trabalho com aqueles cujos valores são strings (que têm um split()método) -que é o tema desta questão. Parece que você está tentando usá-lo em um dicionário de dicionários, então não, não funcionaria com eles. Eu também não aprecio votos negativos das pessoas porque elas realmente não entendem a pergunta (e, portanto, o contexto das respostas que estão sendo fornecidas). Atualizarei minha resposta para fazer quando usá-la for apropriada. Portanto, desfaça seu voto negativo.
martineau
3

Sugiro que você salve seus dados usando o formato JSON em vez do formato pickle, pois os arquivos JSON são legíveis por humanos, o que facilita sua depuração, pois seus dados são pequenos. Os arquivos JSON também são usados ​​por outros programas para ler e gravar dados. Você pode ler mais sobre isso aqui

Você precisará instalar o módulo JSON, pode fazê-lo com o pip:

pip install json


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

Isso cria um arquivo json com o nome myfile.

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

Isso lê e armazena os dados myfile.json em um objeto de dados.

Kavin Sabharwal
fonte
2

A menos que você queira realmente manter o dicionário, acho que a melhor solução é usar o csvmódulo Python para ler o arquivo. Em seguida, você obtém linhas de dados e pode alterar member_phoneou o que quiser; finalmente, você pode usar o csvmódulo novamente para salvar o arquivo no mesmo formato que você o abriu.

Código para leitura:

import csv

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

Código para escrever:

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

Obviamente, você precisa adaptar sua change()função:

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
fonte
o que se entende porOf course, you need to adapt your change() function:
kRazzy R
1
na pergunta, um dict foi usado enquanto CSV funciona mais como uma lista
mguijarr
1

Ainda não cronometrei, mas aposto que o h5 é mais rápido que o pickle; o tamanho do arquivo com compactação é quase certamente menor.

import deepdish as dd
dd.io.save(filename, {'dict1': dict1, 'dict2': dict2}, compression=('blosc', 9))
wordsforthewise
fonte
-2

Solução rápida e suja: converta o dict em string e salve em arquivo, por exemplo:

#dict could be anything:

savedict = open('savedict001.txt', 'w')
savedict.write(str(dict))
savedict.close()
Patrick Stacey
fonte
Converter dict em str e saving não funciona, especialmente quando você tem pd.Series ou np.ndarray como suas chaves nas strings.
Arpan Srivastava