当前位置: 首页 > 面试题库 >

为什么json.loads比ast.literal_eval快一个数量级?

束向荣
2023-03-14
问题内容

在回答了有关如何解析包含浮点数数组的文本文件的问题之后,我运行了以下基准测试:

import timeit
import random

line = [random.random() for x in range(1000)]
n = 10000

json_setup = 'line = "{}"; import json'.format(line)
json_work = 'json.loads(line)'
json_time = timeit.timeit(json_work, json_setup, number=n)
print "json: ", json_time

ast_setup = 'line = "{}"; import ast'.format(line)
ast_work = 'ast.literal_eval(line)'
ast_time = timeit.timeit(ast_work, ast_setup, number=n)
print "ast: ", ast_time

print "time ratio ast/json: ", ast_time / json_time

我多次运行此代码,并始终得到以下结果:

$ python json-ast-bench.py 
json: 4.3199338913
ast: 28.4827561378
time ratio ast/json:  6.59333148483

因此,似乎jsonast此用例快了一个数量级。

使用Python 2.7.5+和Python 3.3.2+的结果相同。

问题:

  1. 为什么json.loads这么快?这个问题似乎暗示ast在输入数据(双引号或单引号)方面更灵活
  2. 在某些使用案例中ast.literal_evaljson.loads尽管速度较慢,但我还是更愿意使用它吗?

编辑:
无论如何,如果性能很重要,我建议您使用UltraJSON(正是我在工作中使用的,比使用相同的迷你基准的json快约4倍)。


问题答案:

这两个函数正在解析完全不同的语言-
JSON和Python文字语法。*如前所述literal_eval

提供的字符串或节点只能由以下Python文字结构组成:字符串,字节,数字,元组,列表,字典,集合,布尔值和None

相比之下,JSON仅处理双引号的JavaScript字符串文字(与Python的不太完全相同),JavaScript数字(仅int和float*),对象(大致相当于dict),数组(大致等于列表),JavaScript布尔值(与Python不同)和null

这两种语言碰巧有重叠的事实并不意味着它们是同一语言。

为什么要json.loads这么快?

由于Python文字语法是一种比JSON更复杂,功能更强大的语言,因此解析起来可能会更慢。而且,可能更重要的是,由于Python文字语法不打算用作数据交换格式(实际上,它
应该专门用于该格式),因此没有人会为加快数据交换速度而付出很多努力。****

这个问题似乎暗示ast在输入数据(双引号或单引号)方面更灵活

那,原始字符串文字,以及Unicode vs. bytes字符串文字,以及复数,集合和JSON无法处理的所有其他内容。

在某些情况下,尽管速度较慢,但​​我更愿意在json.loads上使用ast.literal_eval?

是。当您想解析Python文字时,应使用ast.literal_eval。(或者,更好的是,重新考虑您的设计,以便您不想解析Python文字…)

*这是一个模糊的术语。例如,-2不是Python中的文字,而是运算符表达式,但literal_eval可以处理它。当然,元组/列表/字典/集合显示不是文字,但是literal_eval可以处理它们,除了理解也是显示,并且literal_eval不能处理它们。ast模块中的其他功能可以帮助您找出真正的字面值和非字面值,例如ast.dump(ast.parse("expr"))

**例如,"\q"是JSON中的错误。

***从技术上讲,JSON仅处理一种“数字”类型,即浮点数。但是Python的json模块将不带小数点或指数的数字解析为整数,在许多其他语言的JSON模块中也是如此。

****如果您错过了蒂姆·彼得斯(Tim Peters)对以下问题的评论:“
ast.literal_eval使用率太低,没有人觉得值得花时间(和工作,和工作)来加速它。相反,JSON库通常用于解析千兆字节的数据。”



 类似资料:
  • 问题内容: 我有一个字典,它以字符串形式存储在db字段中。我试图将其解析为字典,但给我一个错误。 为什么会失败并起作用?一个比另一个更好吗? 问题答案: 失败,因为您的值不是有效的JSON文档。在有效文档中,字符串用双引号引起来,并且没有类似将字符串转换为unicode的方法。 使用方法将文档反序列化 在需要评估评估表达式时使用。如果您有Python表达式作为您要评估的输入。 一个比另一个更好吗?

  • 问题内容: 为什么字面上的评估失败,而没有呢? 该文档没有对此进行解释。 我在回答以下问题后发现了这个问题:获取字符串的结果。 问题答案: 接受评估的数据,因为(复数*)是有效的文字。同样适用于。为了使代码简单,没有尝试排除或将其作为二进制运算符。 不允许其他运算符;该函数 应该 只接受文字,不接受表达式。 换句话说,这是一个错误,但如果不中断对构造复数的支持,就很难修复该错误。该实现将使用范围限

  • 问题内容: 示例代码在这里 问题答案: 我认为速度更快,因为使用矢量化方式和熊猫构建在此数组上。 慢,因为它使用。 操作是最快的,然后是。 请参阅此答案,并更好地解释pandas开发人员。

  • 问题内容: 我不知道为什么numba在这里击败numpy(超过3倍)。我在这里进行基准测试时是否犯了一些根本性的错误?对于numpy来说似乎是完美的情况,不是吗?请注意,作为检查,我还运行了一个结合了numba和numpy的变体(未显示),正如预期的那样,它与不带numba的numpy运行相同。 (顺便说一下,这是一个后续问题:数字处理二维数组的最快方法:dataframe vs series v

  • 我读到了关于b/w recyclerview和listview的区别,发现RecyclerViewer比listview更快。 我尝试在线搜索,但没有找到任何令人满意的答案,我知道它使用了ViewHolder模式和通知适配器,但它的内在功能是什么,所以它更快?

  • 问题内容: 为了在工作中进行演示,我想比较NodeJS和C的性能。这是我写的: Node.js(for.js): 我使用GCC编译for.c并运行它: 结果: 然后我在NodeJS中尝试了它: 结果: 在运行了无数次之后,我发现无论如何它都是成立的。如果我将for.c切换double为long在循环中使用a而不是a ,则C花费的时间甚至更长! 不是试图发动火焰战争,但是为什么执行相同操作的Node