Как сериализовать словарь Python в строку, а затем вернуться к словарю? Словарь будет иметь списки и другие словари внутри него.
Как я могу сериализовать словарь Python в строку, а затем вернуться к словарю?
Ответ 1
Это зависит от того, для чего вы хотите его использовать. Если вы просто пытаетесь его сохранить, вы должны использовать pickle
(или, если вы используете CPython 2.x, cPickle
, что быстрее).
>>> import pickle
>>> pickle.dumps({'foo': 'bar'})
b'\x80\x03}q\x00X\x03\x00\x00\x00fooq\x01X\x03\x00\x00\x00barq\x02s.'
>>> pickle.loads(_)
{'foo': 'bar'}
Если вы хотите, чтобы он был доступен для чтения, вы можете использовать json
:
>>> import json
>>> json.dumps({'foo': 'bar'})
'{"foo": "bar"}'
>>> json.loads(_)
{'foo': 'bar'}
json
, однако, очень ограничен в том, что он будет поддерживать, в то время как pickle
может использоваться для произвольных объектов (если он не работает автоматически, класс может определить __getstate__
чтобы точно указать, как его следует мариновать).
>>> pickle.dumps(object())
b'\x80\x03cbuiltins\nobject\nq\x00)\x81q\x01.'
>>> json.dumps(object())
Traceback (most recent call last):
...
TypeError: <object object at 0x7fa0348230c0> is not JSON serializable
Ответ 2
Используйте Python json модуль, или simplejson если у вас нет python 2.6 или выше.
Ответ 3
Если вы полностью доверяете строке и не заботитесь о атаках инъекции python, то это очень простое решение:
d = { 'method' : "eval", 'safe' : False, 'guarantees' : None }
s = str(d)
d2 = eval(s)
for k in d2:
print k+"="+d2[k]
Если вы более безопасны, то ast.literal_eval
- лучшая ставка.
Ответ 4
Pickle отлично, но я думаю, что стоит упомянуть literal_eval
из модуля ast
для еще более легкого весового решения, если вы только сериализуете базовые типы python. Это в основном "безопасная" версия пресловутой функции eval
, которая позволяет оценивать базовые типы python, а не любой действительный код python.
Пример:
>>> d = {}
>>> d[0] = range(10)
>>> d['1'] = {}
>>> d['1'][0] = range(10)
>>> d['1'][1] = 'hello'
>>> data_string = str(d)
>>> print data_string
{0: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], '1': {0: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 1: 'hello'}}
>>> from ast import literal_eval
>>> d == literal_eval(data_string)
True
Одно из преимуществ заключается в том, что сериализованные данные - это всего лишь код python, поэтому он очень дружелюбен к человеку. Сравните это с тем, что вы получили бы с помощью pickle.dumps
:
>>> import pickle
>>> print pickle.dumps(d)
(dp0
I0
(lp1
I0
aI1
aI2
aI3
aI4
aI5
aI6
aI7
aI8
aI9
asS'1'
p2
(dp3
I0
(lp4
I0
aI1
aI2
aI3
aI4
aI5
aI6
aI7
aI8
aI9
asI1
S'hello'
p5
ss.
Недостатком является то, что, как только данные включают тип, который не поддерживается literal_ast
, вам придется перейти к чему-то еще, как травление.
Ответ 5
Одна вещь json
не может сделать, это dict
с индексом с цифрами. Следующий фрагмент
import json
dictionary = dict({0:0, 1:5, 2:10})
serialized = json.dumps(dictionary)
unpacked = json.loads(serialized)
print unpacked[0]
будет бросать
KeyError: 0
Поскольку ключи преобразуются в строки. cPickle
сохраняет числовой тип, и распакованный dict
может быть использован сразу.
Ответ 6
Хотя не строго сериализация, json может быть разумным подходом здесь. Это будет обрабатывать вложенные dicts и списки и данные, пока ваши данные "просты": строки и базовые числовые типы.
Ответ 7
pyyaml также следует упомянуть здесь. Он является читаемым человеком и может сериализовать любой объект python.
Здесь находится pyyaml:
https://bitbucket.org/xi/pyyaml
Ответ 8
Если вы пытаетесь только сериализовать, то pprint также может быть хорошим вариантом. Он требует, чтобы объект был сериализован и потоком файлов.
Вот код:
from pprint import pprint
my_dict = {1:'a',2:'b'}
with open('test_results.txt','wb') as f:
pprint(my_dict,f)
Я не уверен, можно ли легко десериализовать. Я использовал json для сериализации и deserialze раньше, который работает правильно в большинстве случаев.
f.write(json.dumps(my_dict, sort_keys = True, indent = 2, ensure_ascii=True))
Однако в одном конкретном случае были ошибки, записывающие данные не-unicode в json.