Python 字符串脱引号的三大法宝(eval,literal_eval,json.loads)详解

本贴最后更新于 344 天前,其中的信息可能已经时移世改

在使用Python代码进行自动化测试的时候,总是会遇到一些数据类型需要进行转化,比如做接口测试的时候从excel表里读取出来的数据就是字符串,但是需要用代码发送接口请求就需要转化为字典。那么这种场景可以怎么进行转化呢?

有如下方法都可以实现字符串转化为字典:

  1. 使用eval()函数
  2. 使用ast.literal_eval()函数
  3. 使用json.loads()函数

我们来分别解释一下这三种方法如何工作的。

eval()函数

eval函数是Python中做数据类型转化用的比较多的方法。他的作用就是把数据还原成它本身或者能够转化的数据类型。它可以运算字符串里的Python的表达式。

我们来看如下的案例:

1)eval获取字符串里的元组

a = '(1,2,3,4)'
a = eval(a)
print(a,type(a))

结果:
(1, 2, 3, 4) <class 'tuple'>

2)eval获取字符串里的字典

a = '{"name":"lemon","passwd":"123456"}'
a = eval(a)
print(a,type(a))

结果:
{'name': 'lemon', 'passwd': '123456'} <class 'dict'>

3) eval可以运算字符串里的Python表达式:

a = '5 > 6'
print(eval(a))

结果:False 

甚至可以完成如下的功能,通过变量内容作为函数名字,使用eval转化后可以直接调用函数:

# 赋值函数名称
a = "b()"
# 定义函数
def b():
    print(123)
# 通过变量调用函数
eval(a)

由上可见:eval()函数的功能还是非常的强大的,不过也存在一些安全隐患和问题:

read_path = "__import__('os').getcwd()"
print("正常输出:",read_path)
print("转换输出:",eval(read_path))

结果:
正常输出: __import__('os').getcwd()
转换输出: D:\Pycharm_Project\pythonProject70\day16接口测试电商项目实战\01_扩展知识
a = '{"name:":"lemon","age":false}'
print(eval(a))

结果:
NameError: name 'false' is not defined

ast.literal_eval()函数

这个ast模块是用来帮助Python应用开处理抽象的语法解析的,literal_eval()是该模块下的函数,会判断需要计算的内容计算后是不是合法的Python类型,如果是则进行运算,否则就不进行运行。

所以,这个函数可以更加安全地解析字符串中的Python字面量结构,会判断需要计算的内容计算后是不是合法的python类型,相较于eval()较安全。

比如上面的获取系统地址的字符串转化就会报错,不会直接去执行里面的代码:

read_path = "__import__('os').getcwd()"
print("正常输出:",read_path)
print("转换输出:",ast.literal_eval(read_path))

结果:
正常输出: __import__('os').getcw
ValueError: malformed node or string: <ast.Call object at 0x000001E8357EBE20>

而对于合法的python表达式,会进行运算和转化:

a = '{"name":"lemon","passwd":"123456"}'
a = ast.literal_eval(a)
print(a,type(a))

结果:
{'name': 'lemon', 'passwd': '123456'} <class 'dict'>

json.loads()函数

json库是Python的第三方库,json.loads()函数是用来读取json的字符串类型的数据,并且将读取的结果返回为python的dict对象。

它只是纯粹的将json字符串转换成python字典,无法进行引号里的计算功能。

转化字符串为字典:

string = '{"a": 1, "b": 2, "c": 3}'
dict1 = json.loads(string)
print(dict1,type(dict1))

结果:
{'a': 1, 'b': 2, 'c': 3} <class 'dict'>

但是这个json.loads的方法要注意,转化的字符串必须要是json语法规范的字符串,否则无法转化会报错:

string = '{"a": 1, "b": 2, "c": False}'  # False不是json格式字符串
dict1 = json.loads(string)
print(dict1,type(dict1))

结果:
json.decoder.JSONDecodeError: Expecting value: line 1 column 23 (char 22)
json的格式要求,它的值只能是以下类型:

所以,json.loads方法遇到非以上的规范的字符串,转化都会失败报错。

总结对比区别:

  1. ast.literal_eval():这个函数可以安全地解析字符串中的Python字面量结构,如列表、元组、字典等。它比eval()更安全,因为它不会执行字符串中的任何代码。
  2. json.loads():这个函数用于将JSON格式的字符串转换为字典。它只能处理符合JSON格式的字符串,如果字符串中包含其他类型的数据,可能会抛出异常。
  3. eval():这个函数可以将字符串作为Python表达式进行求值,并返回结果。但是,由于它可能执行字符串中的任何代码,所以使用时需要特别小心,避免执行恶意代码。

总结:ast.literal_eval()json.loads()适用于处理复杂的数据结构,而eval()适用于处理简单的数据结构。在选择方法时,需要根据字符串的具体内容和需求来选择合适的方法。

回帖
请输入回帖内容 ...