Python中的eval、ast.literal_eval和JSON decode之间的区别

16
我将2 MB的数据从字符串转换为字典。输入数据是序列化为JSON格式的。
目前,我使用ast.literal_eval并获得所需的字典。但是我试过直接运行eval函数,似乎速度更快,并且返回的结果也一样。
那么,当eval函数可以正常工作时,是否使用ast模块或json模块有任何理由?

1
eval存在安全威胁。仅在您绝对控制eval执行内容时使用。 - jldupont
如果您想将字典与代码一同发布,您也可以将其放置在 Python 模块中并导入它。这样,您就清楚地表明了这是 Python 代码。 - Sven Marnach
4个回答

34

我不太喜欢stackoverflow(和其他地方)的这种态度,他们没有给人们提供任何上下文就告诉他们他们正在做的事情是不安全的,而且他们不应该那样做。也许这只是一个用于导入一些数据的即时脚本,在这种情况下,为什么不选择最快或最方便的方式呢?

然而,在这种情况下,json.loads 不仅更加安全,而且速度更快(根据您的数据,速度可以提高4倍以上)。

In [1]: %timeit json.loads(data)
10000 loops, best of 3: 41.6 µs per loop

In [2]: %timeit eval(data)
10000 loops, best of 3: 194 µs per loop

In [3]: %timeit ast.literal_eval(data)
1000 loops, best of 3: 269 µs per loop

如果您仔细考虑,就会发现JSON比Python更受限制,因此使用优化的解析器解析JSON必须更快。


2
Stack Overflow 不仅是关于回答原始问题的,它也成为了其他人阅读的参考资料。 - Mark E. Haase

25

是的,有一个明显的原因: eval() 是邪恶的。 有一天你的代码可能会读取不受信任的数据,并且这将允许攻击者在您的计算机上运行任意代码。

您也不应使用 ast.literal_eval() 来解码 JSON。它无法解码每个有效的 JSON 字符串,也不适用于此目的。只需使用 json.loads(),它相当快速。


1
如果他们只能在自己的机器上运行它怎么办?(例如:他们下载并运行它) - MxLDevs
2
@Keikoku:所以如果这不是你的机器,你就不在乎了? - Sven Marnach
我猜他们可以把它散播出去,做一些可疑的事情,并将我的工作归功于我。 - MxLDevs
1
那么定义一个名为 Pyson 的神奇的 Python/Python 交换/存储格式如何?它的唯一规范是:任何可以被 ast.literal_eval() 正确解析的内容都可以被解析。 - yota

16

不会。除非您遇到以下两种情况之一:

  1. 那不是JSON!

    有人在文件中放置了__import__('os').system('rm -rf /')。你完蛋了。

  2. 它是JSON,但不是类似Python的部分!

    有人在其中任意位置放置了truefalsenull或Unicode转义符号。生日快乐。


eval(json_str, {'false': False, 'true': True, 'null': None, '__builtins__': {}}) 怎么样?;-) - Nas Banov
3
@NasBanov: 请查看http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html。该文章阐述了“eval”函数的危险性,并提供了更安全的替代方法。 - Janus Troelsen
@JanusTroelsen,是的-请参见此https://dev59.com/zlrUa4cB1Zd3GeqPoOM2#BYbinYgBc1ULPQZF-OBe时间上似乎也有关系 - Nas Banov
@NasBanov:现在尝试一下 json_str = '"\\u2603"'预期输出是 u'\u2603'。但实际上你会得到 '\\u2603'。你也无法解决这个问题。 - Martijn Pieters

2

并不是回答,但应该注意evalliteral_eval不是同一件事。 ast.literal_eval不会运行任意代码。

话虽如此,我同意使用JSON; 我只是想指出eval!= literal_eval


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接