最近在工作中遇到了一个小问题, 如果要将字符串型的数据转换成 dict 类型, 我第一时间就想到了使用 JSON 函数. 但是里面出现了一些问题
1, 通过 JSON 来转换:
- In [1]: import JSON
- In [2]: mes = '{"InsId": 2,"name":"lege-happy","CreationTime":"2019-04-23T03:18:02Z"}'
- In [3]: mes_to_dict = JSON.loads(mes)
- In [4]: print type(mes_to_dict)
- <type 'dict'>
以上的方式转换是没问题的, 但是加入 mes 的格式为 mes = '{"InsId": 2,"name":"lege-happy","CreationTime":"2019-04-23T03:18:02Z"}'的时候使用 JSON 来转换的时候又会发生什么呢?
- In [5]: import JSON
- In [6]: mes = "{'InsId': 1,'name':'lege-error','CreationTime':'2019-04-24T03:18:02Z'}"
- In [7]: mes_to_dict = JSON.loads(mes)
- ---------------------------------------------------------------------------
- ValueError Traceback (most recent call last)
- <ipython-input-7-77264851f35b> in <module>()
- ----> 1 mes_to_dict = JSON.loads(mes)
- /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/JSON/__init__.pyc in loads(s, encoding, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)
- 336 parse_int is None and parse_float is None and
- 337 parse_constant is None and object_pairs_hook is None and not kw):
- --> 338 return _default_decoder.decode(s)
- 339 if cls is None:
- 340 cls = JSONDecoder
- /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/JSON/decoder.pyc in decode(self, s, _w)
- 364
- 365 """
- --> 366 obj, end = self.raw_decode(s, idx=_w(s, 0).end())
- 367 end = _w(s, end).end()
- 368 if end != len(s):
- /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.pyc in raw_decode(self, s, idx)
- 380 """
- 381 try:
- --> 382 obj, end = self.scan_once(s, idx)
- 383 except StopIteration:
- 384 raise ValueError("No JSON object could be decoded")
- ValueError: Expecting property name: line 1 column 2 (char 1)
所以使用 JSON 进行转换存在一个潜在的限制:
由于 JSON 语法规定 数组或对象之中的字符串必须使用双引号, 不能使用单引号 (官网上有一段描述是 "A string is a sequence of zero or more Unicode characters, wrapped in double quotes, using backslash escapes" ), 因此上面的转换是错误的:
通过 eval 来转换:
- In [8]: mes = '{"InsId": 2,"name":"lege-happy","CreationTime":"2019-04-23T03:18:02Z"}'
- In [9]: mes_dict = eval(mes)
- In [10]: print type(mes_dict)
- <type 'dict'>
- In [11]:
- In [11]: mes = mes = "{'InsId': 1,'name':'lege-error','CreationTime':'2019-04-24T03:18:02Z'}"
- In [12]: mes_dict = eval(mes)
- In [13]: print type(mes_dict)
- <type 'dict'>
上面的例子可以看出进行转换的时候不存在使用 JSON 转换的问题, 但是我们需要注意的是使用 eval 会存在安全问题, 比如:
串型的输入直接计算. 比如, 她会将'1+1'的计算串直接计算出结果.
- In [14]: value = eval(raw_input('please input a value string:'))
- please input a value string:2 + 2
- In [15]: value
- Out[15]: 4
从上面来看, eval 功能可谓非常强大, 即可以做 string 与 list,tuple,dict 之间的类型转换, 还可以做计算器使用! 更有甚者, 可以对她能解析的字符串都做处理, 而不顾忌可能带来的后果! 所以说 eval 强大的背后, 是巨大的安全隐患!!!
比如说用户恶意输入下面的字符串:
- open(r'D://filename.txt', 'r').read()
- __import__('os').system('dir')
- __import__('os').system('rm -rf /etc/*')
那么 eval 就会显示你电脑目录结构, 读取文件, 删除文件等等. 如果是格盘等更严重的操作, 她也会照做不误!!! 显然这个不符合我们的需求!
通过 literal_eval 转换:
- In [20]: import ast
- In [21]: mes = '{"InsId": 2,"name":"lege-happy","CreationTime":"2019-04-23T03:18:02Z"}'
- In [22]: mes_dict = ast.literal_eval(mes)
- In [23]: print type(mes_dict)
- <type 'dict'>
- In [24]:
- In [24]:
- In [24]: mes = mes = "{'InsId': 1,'name':'lege-error','CreationTime':'2019-04-24T03:18:02Z'}"
- In [25]: mes_dict = ast.literal_eval(mes)
- In [26]: print type(mes_dict)
- <type 'dict'>
使用 ast.literal_eval 进行转换既不存在使用 JSON 进行转换的问题, 也不存在使用 eval 进行转换的 安全性问题, 因此推荐使用 ast.literal_eval.
我们来看看官方文档怎么描述 literal_eval 的:
- def literal_eval(node_or_string):
- """
- Safely evaluate an expression node or a string containing a Python
- expression. The string or node provided may only consist of the following
- Python literal structures: strings, numbers, tuples, lists, dicts, booleans,
- and None.
- """
意思说 ast 模块就是帮助 Python 应用来处理抽象的语法解析的. 而该模块下的 literal_eval() 函数: 则会判断需要计算的内容计算后是不是合法的 python 类型, 如果是则进行运算, 否则就不进行运算.
比如说上面的计算操作, 及危险操作, 如果换成了 ast.literal_eval(), 都会拒绝执行.
所以个人推荐大家转换 dict 的时候, 出于安全考虑对字符串进行类型转换的时候, 最好使用 ast.literal_eval() 函数!
来源: http://blog.51cto.com/legehappy/2418264