草庐IT

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

coder 2023-08-19 原文

在回答关于 how to parse a text file containing arrays of floats 的问题后,我运行了以下基准测试:

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

看来 json几乎比 ast 快一个数量级对于这个用例。

我在 Python 2.7.5+ 和 Python 3.3.2+ 上得到了相同的结果。

问题:

  1. 为什么 json.loads 这么快? This question似乎暗示 ast 对于输入数据(双引号或单引号)更灵活
  2. 是否存在我更愿意使用 ast.literal_eval 而不是 json.loads 的用例,尽管它速度较慢?

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

最佳答案

这两个函数正在解析完全不同的语言——JSON 和 Python 文字语法。* As literal_eval说:

The string or node provided may only consist of the following Python literal structures: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None.

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

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


Why is json.loads so much faster ?

因为 Python 文字语法是一种比 JSON 更复杂、更强大的语言,它的解析速度可能更慢。而且,可能更重要的是,因为 Python 文字语法不打算用作数据交换格式(事实上,它特别应该用于此),没有人可能会付出太多努力使其能够快速进行数据交换。****

This question seems to imply that ast is more flexible regarding the input data (double or single quotes)

还有原始字符串文字、Unicode 与字节字符串文字、复数、集合以及 JSON 无法处理的各种其他内容。

Are there use cases where I would prefer to use ast.literal_eval over json.loads although it's slower ?

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


* 这是一个有点模糊的术语。例如,-2 不是 literal在 Python 中,但是一个运算符表达式,但是 literal_eval可以处理它。当然 tuple/list/dict/set 显示不是文字,但 literal_eval 可以处理它们——除了理解也是显示,而 literal_eval 不能处理它们。 ast 模块中的其他函数可以帮助您找出什么是文字,什么不是文字——例如,ast.dump(ast.parse("expr")) .

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

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

**** 如果您错过了 Tim Peters 对以下问题的评论:“ast.literal_eval 的使用率如此之低,以至于没有人认为值得花时间在加速它。相比之下,JSON 库通常用于解析千兆字节的数据。”

关于python - 为什么 json.loads 比 ast.literal_eval 快一个数量级?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21223392/

有关python - 为什么 json.loads 比 ast.literal_eval 快一个数量级?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  3. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  4. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  5. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  6. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  7. ruby - 无法让 RSpec 工作—— 'require' : cannot load such file - 2

    我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳

  8. ruby-on-rails - Rails HTML 请求渲染 JSON - 2

    在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这

  9. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

    它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

  10. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

随机推荐