Как сериализовать словарь Python в строку, а затем вернуться в словарь? - PullRequest
58 голосов
/ 03 декабря 2010

Как мне сериализовать словарь Python в строку, а затем вернуться в словарь? В словаре будут списки и другие словари.

Ответы [ 8 ]

95 голосов
/ 03 декабря 2010

Это зависит от того, для чего вы хотите его использовать.Если вы просто пытаетесь сохранить его, вы должны использовать 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
10 голосов
/ 03 декабря 2010

Используйте модуль Python json или simplejson , если у вас нет Python 2.6 или выше.

9 голосов
/ 09 июля 2015

Если вы полностью доверяете строке и не заботитесь о атаках с использованием 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.

8 голосов
/ 21 июня 2015

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, вам придется переходить к чему-то другому, например, к травлению.

4 голосов
/ 24 апреля 2017

Одна вещь, которую 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 можно использовать сразу.

1 голос
/ 27 июля 2013

pyyaml ​​ также следует упомянуть здесь.Он доступен для чтения человеком и может сериализовать любой объект python.
pyyaml ​​находится здесь:
https://bitbucket.org/xi/pyyaml

1 голос
/ 03 декабря 2010

Хотя это не строго сериализация, здесь может быть разумным использование json. Это будет обрабатывать вложенные запросы и списки, а также данные, если ваши данные «просты»: строки и основные числовые типы.

0 голосов
/ 04 декабря 2013

Если вы пытаетесь только сериализовать, то pprint также может быть хорошим вариантом.Это требует сериализации объекта и потока файлов.

Вот некоторый код:

from pprint import pprint
my_dict = {1:'a',2:'b'}
with open('test_results.txt','wb') as f:
    pprint(my_dict,f)

Я не уверен, сможем ли мы легко десериализоваться.Ранее я использовал json для сериализации и десериализации, что в большинстве случаев работает корректно.

f.write(json.dumps(my_dict, sort_keys = True, indent = 2, ensure_ascii=True))

Однако в одном конкретном случае были некоторые ошибки при записи данных, отличных от Юникода, в json.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...