我有一个字典,它以字符串的形式存储在db字段中,我试图将它解析成一个dict,但是json.loads
给了我一个错误。
为什么json.loads
在这方面失败了而ast.literal_eval
可以工作?是一个比另一个更好吗?
>>> c.iframe_data
u"{u'person': u'Annabelle!', u'csrfmiddlewaretoken': u'wTE9RZGvjCh9RCL00pLloxOYZItQ98JN'}"
# json fails
>>> json.loads(c.iframe_data)
Traceback (most recent call last):
ValueError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
# ast.literal_eval works
>>> ast.literal_eval(c.iframe_data)
{u'person': u'Annabelle!', u'csrfmiddlewaretoken': u'wTE9RZGvjCh9RCL00pLloxOYZItQ98JN'}
7条答案
按热度按时间des4xlb01#
json.loads
失败,因为您的c.iframe_data
值不是有效的JSON文档。在有效的json
文档中,字符串用双引号引起来,并且没有类似u
的用于将字符串转换为Unicode的格式。使用
json.loads(c.iframe_data)
意味着在c.iframe_data
中反序列化JSON
文档ast.literal_eval
在你需要eval来计算input
表达式时使用。如果你有Python表达式作为你想要计算的输入。一个比另一个更好吗?
这取决于数据。请参阅此answer了解更多上下文。
uinbv5nw2#
我有一个字典,它以字符串形式存储在db字段中。
这是一个设计上的错误,虽然完全有可能,就像有人已经做的那样,提取字典的
repr
,但不能保证对象的repr
可以被求值。在只存在字符串键、字符串值和数值的情况下,大多数时候Python
eval
函数将从其repr中重新生成值,但是我不知道为什么您认为这会使它成为有效的JSON。我试图将其解析为一个dict,但是json.loads给了我一个错误。
当然,因为JSON没有存储在数据库中,所以期望它解析为JSON似乎是不合理的。虽然有趣的是,
ast.literal_eval
可以用来解析值,但除了相对简单的Python类型之外,没有任何保证。既然你的数据看起来确实局限于这些类型,你的问题的真实的解决方案是纠正数据存储的方式,通过在存储到数据库之前将字典转换成一个字符串
json.dumps
.一些数据库系统(* 例如 *,PostgreSQL)有JSON类型,使查询这样的数据更简单,我建议你使用这样的类型,如果他们对你可用.至于哪个“更好”,这将取决于具体的应用程序,但JSON被明确设计为一种紧凑的人类可读、机器可解析的格式,用于简单的结构化数据,而您当前的表示是基于Python特定的格式,(例如)在其他语言中很难计算,JSON是这里适用的标准,您将从使用它中受益。
93ze6v8z3#
json.loads
专门用于解析JSON,这是一种非常严格的格式。没有u'...'
语法,所有字符串都用双引号分隔,而不是用单引号分隔。使用json.dumps
可以序列化json.loads
可以读取的内容。所以
json.loads(string)
是json.dumps(object)
的逆,而ast.literal_eval(string)
(模糊地)是repr(object)
的逆。JSON很好,因为它是可移植的--几乎每种语言都有它的解析器,所以如果你想把JSON发送到Javascript前端,你不会有任何问题。
ast.literal_eval
不容易移植,但功能稍微丰富一些:例如,可以使用元组、集合和字典,它们的键不限于字符串。也叫
json.loads
is significantly faster thanast.literal_eval
。oymdgrw74#
因为
u"{u'person': u'Annabelle!', u'csrfmiddlewaretoken': u'wTE9RZGvjCh9RCL00pLloxOYZItQ98JN'}"
是Python Unicode字符串,而不是Javascript对象表示法,所以在chrome控制台中:或者可以使用Yaml来处理它:
mftmpeh85#
首先,也是最重要的一点,不要对数据进行两次序列化。数据库本身就是一个数据序列化过程,它有一组丰富的、富有表现力的工具来查询、探索、操作和呈现数据。序列化数据以便随后放入数据库中,消除了孤立的子组件更新、子组件查询和索引的可能性,并将所有写入耦合到强制的初始读取。几个最重要的问题。
其次,Java Script Object Notation (JSON)是JavaScript语言的一个有限子集,适合于表示数据交换服务中的静态数据,作为 language 的一个子集,这意味着您可以在JS中简单地使用
eval
来重构原始对象。(没有诸如内部引用、模板定义类型扩展),具有内置的JavaScript语言的限制以及对使用需要大量“转义”的字符串的惩罚。结束标记的使用也使得它很难在纯流场景中使用,例如,你不能“终结”一个对象,直到命中它的配对}
,因此它也没有记录分隔标记。其他限制的显著例子包括在JSON中传递HTML需要过多的转义,所有数字都是浮点数(54位整数精度、舍入误差等),这显然不适合于存储或传输金融信息或使用需要64位整数、没有本机日期表示等的技术(例如加密)。作为语言,JS和Python之间存在一些显著的差异,因此JSON的“JavaScript对象表示法”与PLS的区别也是如此(Python Literal Syntax)behavior.碰巧的是,为了定义文本,大多数JavaScript文本语法都直接与Python兼容,尽管解释略有不同。反之则不成立。请看上面的例子。2如果你关心的是为Python保持数据的保真度,Python常量比它们的JS等价物更有表现力,更少“损耗”。3然而,正如其他答案/评论所指出的,
repr()
不是生成该表示的可靠方式;Python的字面语法并不是要这样使用,为了最大程度的类型保真度,我通常推荐YAML序列化,JSON是它的一个完全有效的子集。仅供参考,为了解决与实体关联的字典式Map的存储的实际问题,有entity-attribute-value data models。关系数据库FTW中的任意键值存储,但伴随权力而来的是责任。请谨慎使用此模式,并且仅在绝对需要时使用。(如果这是一种常见模式,请查看文档存储。)
fhity93d6#
json.loads
应该比ast.literal_eval
更适合解析JSON,原因如下(总结其他海报)。在您的特定示例中,您的输入是非法的/格式错误的JSON,使用Python 2.x以错误的方式导出(所有不需要的和非法的
u'
前缀),无论如何,Python 2.x本身即将停产,请转到Python 3.x。您可以简单地使用正则表达式来修复/预处理:json.loads
的合理理由,但可以重新访问您的架构。至少只需对所有字符串运行一次修复正则表达式,然后将法律的的JSON存储回去)json.loads
优点/缺点:ast.literal_eval
不同***慢。**有更快的JSON库,如
ultrajson, yajl, simplejson
等。此外,对于大型导入作业,您可以使用多处理/多线程(这也可以防止内存泄漏,这是所有解析器的常见问题)。***数值字段:**将所有整数、长整数和浮点数转换为双精度,可能会丢失精度(@amcgregor)
3j86kqsm7#
在我的例子中,我跳过了
ast.literal_eval(selected_cell_from_db)
,它不是从单引号引用的dict生成JSON dict(尽管它可以计算它,但它是string类型),我可以在包DeepDiff中使用它。当保存对象时,我需要使用
json.dumps(obj_to_save_to_db)
而不是str(obj_to_save_to_db)
.json.dumps创建一个双引号的、json可读的字符串;str()不需要),然后
json.loads(selected_cell_from_db)
。