如何将Python字典序列化为字符串,然后再返回字典?


Answers:


116

这取决于您要使用它的目的。如果只是尝试保存它,则应使用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

18
我希望我知道-1是什么意思。
克里斯·摩根

7
我想这个-1可能是因为它没有提到酸洗中固有的安全性问题。参见stackoverflow.com/questions/10282175/attacking-pythons-pickle
Piotr Dobrogost,2014年

值得一提的是,答案的cPickle部分与python 3.x不相关。请参阅此处获取官方说明。简而言之,包的加速C版本应该是任何python模块的默认选择,并且如果不可用,则模块本身将退回到python实现。这封装了用户的实现。报价:In Python 3.0... Users should always import the standard version, which attempts to import the accelerated version and falls back to the pure Python version.
Ori

警告泡菜模块不安全。只能释放您信任的数据。” -文档
ArtuX '20

11

使用Python的json模块,如果您没有python 2.6或更高版本,请使用simplejson


3
+1:json比泡菜更好,并且可以用相同的方式使用:json.dumps(mydict)json.loads(mystring)
nosklo 2010年

11
但是json只能执行字符串,数字,列表和字典,而pickle可以执行任何python类型,但是json相比于pickle可以执行的类型具有更高的可移植性
Dan D.

使用时json.dumps(),请注意某些类型(FalseTrueNone),因为它们与json
Jason Heo

10

如果您完全信任该字符串并且不关心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是更好的选择。


老实说,这是我一直使用的方法。感谢您分享安全提示。如果字典包含可以通过repr字符串初始化的定制对象,则我使用repr而不是str
Evan Pu

1
您应该ast.literal_eval默认使用。eval具有零附加值和很大的安全问题。
让·弗朗索瓦·法布尔

发生不好的事情是因为人们诚实地认为在他们特定的代码和平中不存在安全隐患,因此他们可以开心地eval走开。每次我都感到很恶心,有人提倡这种卑鄙的文化。只需使用json.dumpsjson.loads(或任何其他非eval解决方案),没有真正的理由不这样做
ArtuX

10

Pickle很棒,但是如果您只序列化基本的python类型,那么我认为值得literal_evalast模块中提供更轻量的解决方案。这基本上是臭名昭著的“安全”版本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可以立即使用解压后的数字。


1

尽管不是严格的序列化,但json在这里可能是合理的方法。只要您的数据“简单”即可处理嵌套的字典和列表以及数据:字符串和基本数字类型。


1

pyyaml也应该在这里提到。它是人类可读的,并且可以序列化任何python对象。
pyyaml托管在这里:https ://bitbucket.org/xi/pyyaml


-2

如果您只尝试序列化,那么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))

但是,在一种特定情况下,将非Unicode数据写入json会出现一些错误。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.