Converter um dict python em uma string e vice-versa

275

Estou escrevendo um programa que armazena dados em um objeto de dicionário, mas esses dados precisam ser salvos em algum momento durante a execução do programa e carregados de volta no objeto de dicionário quando o programa é executado novamente. Como converter um objeto de dicionário em uma sequência que pode ser gravada em um arquivo e carregada de volta em um objeto de dicionário? Esperamos que isso suporte dicionários que contenham dicionários.

AJ00200
fonte

Respostas:

274

O módulo json é uma boa solução aqui. Tem as vantagens sobre o pickle, que produz apenas saída de texto sem formatação e é multiplataforma e entre versões.

import json
json.dumps(dict)
Tyler Eaves
fonte
2
Vou dar uma olhada neste módulo também. Tanto o json quanto o pickle parecem fáceis de usar, então tudo se resume a coisas como suporte entre plataformas. Graças
AJ00200
5
Pickle tende a ser visto como bastante obsoleto neste momento. Eu sempre uso o json para coisas assim. Ser (relativamente) legível por humanos é muito GRANDE, na maior parte do tempo.
Tyler Eaves
30
Você deve adicionar um exemplo simples para permitir que os usuários vejam como fazer isso.
Miguel Vazq 23/09
1
@TylerEaves Você pode dar um exemplo de como isso deve ser feito.
Boban
1
: foreheadslap: não se esqueça do import jsonque eu fiz!
Jesse Chisholm
207

Se o seu dicionário não for muito grande, talvez o str + eval possa fazer o trabalho:

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

dict2 = eval(str1)

print dict1==dict2

Você pode usar ast.literal_eval em vez de eval para obter segurança adicional se a fonte não for confiável.

PabloG
fonte
13
Não estou realmente preparado para lidar com as possíveis explorações que isso poderia introduzir no código. Não sei quais problemas o json ou o pickle podem ter, mas sei que a avaliação seria perigosa nesse caso.
AJ00200
5
@ AJ00200: e a alternativa ast.literal_eval que mencionei ?. Na ajuda do Python: "Avalie com segurança um nó de expressão ou uma string que contém uma expressão Python. A string ou o nó fornecido pode consistir apenas nas seguintes estruturas literais do Python: strings, números, tuplas, listas, dicts, booleanos e None. Isso pode ser usado para avaliar com segurança seqüências de caracteres contendo expressões Python de fontes não confiáveis, sem a necessidade de analisar os valores. "
PabloG
Parece útil, mas quando eu estava usando o SQLite anteriormente para lidar com esses dados e ele tinha mais de 1500 entradas, ele é bastante grande e cresce o tempo todo.
AJ00200
164

Eu uso json:

import json

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

# load to dict
my_dict = json.loads(input) 
Eyal Ch
fonte
14

Use o picklemódulo para salvá-lo no disco e carregar posteriormente.

ismail
fonte
2
@extraneon Na verdade, é uma resposta para a pergunta. Ele a converte em uma string em algum lugar e a grava em um arquivo. Não preciso fazer a conversão ou a gravação de arquivos, pois tudo está encapsulado por pickle.
AJ00200
11

Por que não usar a função da biblioteca embutida ast do Python 3 literal_eval . É melhor usar literal_eval em vez de eval

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

dará saída como dicionário real

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

E se você está pedindo para converter um dicionário em uma string , que tal usar o método str () do Python?

Suponha que o dicionário seja:

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

E isso será feito assim:

str(my_dict)

Irá imprimir:

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

Este é o mais fácil que você quiser.

FightWithCode
fonte
5

Se em 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
fonte
1
Essa seria uma resposta melhor se você explicasse como o código fornecido responde à pergunta.
pppery
4

Converter dicionário em JSON (string)

import json 

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

result = json.dumps(mydict)

print(result[0:20])

você receberá:

{"name": "Don", "sur

Converter string em dicionário

back_to_mydict = json.loads(result) 
Harvey
fonte
3

Eu acho que você deve considerar o uso do shelvemódulo que fornece objetos semelhantes a dicionários, baseados em arquivos persistentes. É fácil de usar no lugar de um dicionário "real" porque fornece de maneira quase transparente ao programa algo que pode ser usado como um dicionário, sem a necessidade de convertê-lo explicitamente em uma string e depois gravar em um arquivo (ou vice-versa). versa).

A principal diferença é a necessidade de inicializá- open()lo antes do primeiro uso e depois close()quando você terminar (e possivelmente usá sync()-lo, dependendo da writebackopção que está sendo usada). Qualquer objeto de arquivo "prateleira" criado pode conter dicionários regulares como valores, permitindo que sejam aninhados logicamente.

Aqui está um exemplo trivial:

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

Resultado:

{'three': {'three.1': 3.1, 'three.2': 3.2}, 'two': 2, 'one': 1}
Martineau
fonte
2

Se você se preocupa com a velocidade, use ujson (UltraJSON), que possui a mesma API do 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
fonte
1

Eu uso o yaml para isso, se precisar ser legível (nem JSON nem XML são IMHO), ou se a leitura não for necessária, uso pickle.

Escrever

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)

Leia de volta

from pickle import dumps, loads
rev = loads(open('/var/tmp/dump.txt').read())
print rev
Gerard
fonte
Você realmente deve usar o bsinalizador ao abrir o arquivo aqui.
Piotr Dobrogost
1
Eu poderia ter sido mais explícito. No entanto, o dumps()padrão é o protocolo 0, que é um protocolo ascii. É por isso que 'rb'não é necessário IMHO.
Gerard