Конвертируйте python dict в строку и обратно

275

Я пишу программу, которая хранит данные в объекте словаря, но эти данные необходимо сохранить в определенный момент во время выполнения программы и загрузить обратно в объект словаря при повторном запуске программы. Как бы я преобразовал объект словаря в строку, которую можно записать в файл и загрузить обратно в объект словаря? Надеемся, что это будет поддерживать словари, содержащие словари.

AJ00200
источник

Ответы:

274

Модуль JSON является хорошим решением здесь. Он имеет преимущество перед pickle в том, что он производит только вывод простого текста, а также является кроссплатформенным и кросс-версией.

import json
json.dumps(dict)
Тайлер Карниз
источник
2
Я также посмотрю на этот модуль. И json, и pickle кажутся достаточно простыми в использовании, поэтому речь пойдет о таких вещах, как кроссплатформенная поддержка. Спасибо
AJ00200
5
Пикл, как правило, считается довольно устаревшим на данный момент. Я всегда использую JSON для таких вещей. Быть (относительно) читаемым человеком - БОЛЬШОЙ плюс большую часть времени.
Тайлер Карниз
30
Вы должны добавить простой пример, чтобы пользователи могли видеть, как это сделать.
Мигель Вацк
1
@TylerEaves Можете ли вы привести пример, как это должно быть сделано.
Бобан
1
: foreheadslap: не забывай, import jsonкак я!
Джесси Чисхолм
207

Если ваш словарь не слишком большой, возможно, сработает str + eval:

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

dict2 = eval(str1)

print dict1==dict2

Вы можете использовать ast.literal_eval вместо eval для дополнительной безопасности, если источник не заслуживает доверия.

PabloG
источник
13
Я не очень готов иметь дело с возможными эксплойтами, которые это может внести в код. Я не знаю, какие проблемы могут возникнуть у json или pickle, но я точно знаю, что в этом случае eval будет опасен.
AJ00200
5
@ AJ00200: и альтернативу ast.literal_eval, о которой я упоминал? Из справки Python: «Безопасно оцените узел выражения или строку, содержащую выражение Python. Предоставленная строка или узел может состоять только из следующих литеральных структур Python: строк, чисел, кортежей, списков, диктов, логических значений и None. может использоваться для безопасной оценки строк, содержащих выражения Python из ненадежных источников, без необходимости разбирать значения самостоятельно. "
PabloG
Это кажется полезным, но когда я ранее использовал SQLite для обработки этих данных, в нем было более 1500 записей, так что он довольно большой и постоянно растет.
AJ00200
164

Я использую json:

import json

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

# load to dict
my_dict = json.loads(input) 
Эяль Ч
источник
14

Используйте pickleмодуль, чтобы сохранить его на диск и загрузить позже.

исмаил
источник
2
@extraneon На самом деле, это ответ на вопрос. Он конвертирует его в строку и записывает в файл. Мне не нужно делать фактическое преобразование или запись файла, поскольку все это инкапсулировано маринадом.
AJ00200
12

Почему бы не использовать встроенные в Python 3 Аст функции библиотеки literal_eval . Лучше использовать literal_eval вместо eval

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

выдаст вывод как фактический словарь

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

И если вы просите преобразовать словарь в строку , как насчет использования str () метода Python.

Предположим, словарь:

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

И это будет сделано так:

str(my_dict)

Напечатает:

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

Это легко, как вам нравится.

FightWithCode
источник
5

Если в китайцах

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')
бета
источник
1
Это было бы лучшим ответом, если бы вы объяснили, как предоставленный вами код отвечает на вопрос.
pppery
4

Преобразовать словарь в JSON (строка)

import json 

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

result = json.dumps(mydict)

print(result[0:20])

получит вас:

{"name": "Don", "sur

Конвертировать строку в словарь

back_to_mydict = json.loads(result) 
Харви
источник
3

Я думаю, вы должны рассмотреть возможность использования shelve модуля, который обеспечивает постоянные файловые объекты словаря. Его легко использовать вместо «реального» словаря, потому что он почти прозрачно обеспечивает вашу программу чем-то, что можно использовать так же, как словарь, без необходимости явно преобразовывать его в строку и затем записывать в файл (или наоборот). Versa).

Основное различие заключается в том, что сначала необходимо выполнить open()его перед первым использованием, а затем - close()после завершения (и, возможно sync(), в зависимости отwriteback параметра). Любой созданный файловый объект «полка» может содержать в качестве значений обычные словари, что позволяет им быть логически вложенными.

Вот тривиальный пример:

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

Вывод:

{'three': {'three.1': 3.1, 'three.2': 3.2}, 'two': 2, 'one': 1}
Мартино
источник
2

Если вам важна скорость, используйте ujson (UltraJSON), который имеет тот же API, что и 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]
Томаш Бартковяк
источник
1

Я использую yaml для этого, если он должен быть читаемым (ни JSON, ни XML не являются этим ИМХО), либо если чтение не нужно, я использую pickle

Напишите

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)

Читать назад

from pickle import dumps, loads
rev = loads(open('/var/tmp/dump.txt').read())
print rev
Gerard
источник
Вы должны действительно использовать bфлаг при открытии файла здесь.
Петр Доброгост
1
Я мог бы быть более явным. Однако по dumps()умолчанию используется протокол 0, который является протоколом ascii. Именно поэтому 'rb'ИМХО не нужно.
Джерард