在Python中使用eval()处理JSON?
千万不要这样做。
这个问题还在被点赞,所以我想加个警告。如果你在用Python 3,直接使用自带的json
包就行了。如果你在用Python 2,尽量升级到Python 3。如果你不能使用Python 3(我很遗憾),可以使用James Thompson推荐的simplejson包
。
下面是原始问题。
撇开最佳实践不谈,有没有什么理由不这样做?
我正在为一个Google Code项目写一个提交后钩子,它通过一个JSON对象提供提交数据。GC在请求中提供了一个HMAC认证令牌(在JSON数据之外),通过验证这个令牌,我可以很有信心地认为JSON数据是安全的(因为不太可能不信任Google)并且是有效的。
我自己(简短)的调查表明,JSON恰好是完全有效的Python代码,唯一的例外是"\/"
转义序列——而GC似乎并不会生成这个。
所以,既然我在用Python 2.4(也就是没有json
模块),eval()
看起来真的很诱人。
编辑:为了说明,我并不是在问这是不是个好主意。我非常清楚这不是个好主意,我也很怀疑即使我在这个项目中用过这个技术,未来的项目我也不会再用。我只是想确保我知道如果这样做会遇到什么麻烦。:-)
4 个回答
一个主要的区别是,JSON中的布尔值是 true
或 false
,而在Python中则是 True
或 False
。
最重要的原因是,eval
这个东西绝对不应该用来处理外部输入,因为这样会让人有机会执行任意代码。
最佳实践的意思是,在大多数情况下,不遵循它们是个坏主意。如果我是你,我会用一个解析器把JSON转换成Python。可以试试simplejson,我上次用的时候发现它解析JSON非常简单,而且声称支持Python 2.4。
我不同意不信任Google的说法。我不会完全不信任他们,但我会核实从他们那里得到的数据。其实我之所以会用JSON解析器,正是因为你提到的问题:
我自己(简单)调查发现,JSON在大多数情况下是完全有效的Python,唯一的例外是“/”这个转义序列——而GC似乎不会生成这个。
你为什么认为Google代码永远不会生成这样的转义序列呢?
如果你用对的工具,解析问题是可以解决的。如果你试图走捷径,最终可能会因为错误的假设而受伤,或者像用正则表达式和布尔逻辑拼凑一个解析器一样,明明已经有现成的解析器可以用。
如果你觉得你的脚本运行一段时间后偶尔会在一些不常见的情况下出错,那我建议你使用eval。
但如果你希望你的代码更加稳健,花点时间添加simplejson会更好。你不需要它的C部分来提高速度,所以把几个.py文件放到某个文件夹里其实并不难。
举个可能会让你头疼的例子,JSON使用的是Unicode,而simplejson返回的是Unicode,eval返回的是字符串(str):
>>> simplejson.loads('{"a":1, "b":2}')
{u'a': 1, u'b': 2}
>>> eval('{"a":1, "b":2}')
{'a': 1, 'b': 2}
补充:一个更好的例子来说明eval()的不同表现:
>>> simplejson.loads('{"X": "\uabcd"}')
{u'X': u'\uabcd'}
>>> eval('{"X": "\uabcd"}')
{'X': '\\uabcd'}
>>> simplejson.loads('{"X": "\uabcd"}') == eval('{"X": "\uabcd"}')
False
补充2:今天又看到一个问题,SilentGhost指出:eval没有正确处理true变成True,false变成False,null变成None。
>>> simplejson.loads('[false, true, null]')
[False, True, None]
>>> eval('[false, true, null]')
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
File "<string>", line 1, in <module>
NameError: name 'false' is not defined
>>>