
Json是是一种轻量级的数据交换格式,易于人阅读和编写,现在大多服务的接口数据都使用Json进行传递。测试人员与Json免不了打交道。
Python官方提供了Json库供用户处理Json数据,包括4种方法:
dumps()
loads()
dump()
load()
使用前要导入json模块:
import json
这4种方法基本可以满足测试人员的需求。如果有性能更好、功能更多的需求,可以使用第三方库,如orjson、rapidjson、Pydantic。
本篇详细介绍如何使用json.dumps()
方法。
关于json.dumps()
json.dumps()
能够将Python对象编码成JSON格式的字符串。它接受一个Python对象作为参数,然后将其转换成JSON格式的字符串并返回,方便被其他程序或者编程语言读取。
python 原始类型向 json 类型的转化对照表:
Python | JSON |
---|---|
dict | object |
list, tuple | array |
str, unicode | string |
int, long, float | number |
True | true |
False | false |
None | null |
json.dumps()
方法的基本用法:
json.dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False)
json.dumps()
的各个参数中,obj是必选的,其他参数可选。
obj 参数
obj可以是python的各种对象,比如列表、字典、元组、字符串等
import json
# 假设我们有一个字典
data = {
'name': 'JZY',
'age': 18,
'city': 'HeNan'
}
print(data) # 输出data
print(type(data)) # 将输出data的类型为dict(字典)
json_string = json.dumps(data) # data就是obj
print(json_string) # 输出转换后的data,即json_string
print(type(json_string)) # 将输出json_string类型为json格式的字符串
运行结果
{'name': 'JZY', 'age': 18, 'city': 'HeNan'}
<class 'dict'>
{"name": "JZY", "age": 18, "city": "HeNan"}
<class 'str'>
skipkeys 参数
默认为False。设置为True时,如果遇到字典中的键不是基本类型(即不是str, unicode, int, long, float, bool, None),则跳过该键值对不进行序列化,而不是抛出TypeError异常。skipkeys设置为False(默认值),如果字典中包含非基本类型的键,则
json.dumps()会抛出TypeError异常。
import json
# 假设我们有一个字典,其中包含一个非基本类型的键,即一个元组
data = {
'a': 1,
('b', 'c'): 2, # 这是一个元组作为键,不是基本类型
'd': 3
}
try:
# 默认情况下,这将抛出TypeError
json.dumps(data)
except TypeError as e:
print("TypeError:", e) # 输出错误类型
# 使用skipkeys=True避免错误
json_data = json.dumps(data, skipkeys=True)
print(json_data) # 输出将只包含键'a'和'd',因为('b', 'c')不是基本类型
运行结果
TypeError: keys must be str, int, float, bool or None, not tuple
{"a": 1, "d": 3}
在上面的例子中,如果没有使用skipkeys=True,尝试序列化包含元组作为键的字典将会引发一个TypeError。使用skipkeys=True可以避免这个错误,但会丢失那些无法序列化的键值对。
ensure_ascii 参数
默认为True。设置为True(默认值)时,所有的非ASCII字符(即Unicode字符)都会被转义成ASCII字符。这意味着输出的JSON字符串将只包含ASCII字符,这确保了最大兼容性,因为ASCII是所有Unicode字符集的子集。设置为False时,
json.dumps()会尽可能地输出原始的Unicode字符,而不是使用转义序列。这可以使得输出的字符串更短,且在某些情况下更易于阅读,特别是当处理包含大量非ASCII字符的数据时。
import json
# 假设我们有一个包含非ASCII字符的字符串,ü非ASCII字符,汉字非ASCII字符。
data = {
'name': 'Günter',
'city': '北京'
}
# 默认情况下,ensure_ascii=True,非ASCII字符会被转义
print(json.dumps(data))
# 使用ensure_ascii=False输出原始Unicode字符
print(json.dumps(data, ensure_ascii=False))
运行结果
{"name": "G\u00fcnter", "city": "\u5317\u4eac"}
{"name": "Günter", "city": "北京"}
这个例子中,第一个json.dumps()
调用回转义非ASCII字符,因为默认ensure_ascii=True。
第二个json.dumps()
由于设置ensure_ascii=False,不会转义非ASCII字符。
check_circular 参数
默认为True。设置为True(默认值),
json.dumps()会检查对象中是否存在循环引用,即对象直接或间接地引用自己。如果发现循环引用,将抛出ValueError异常。设置为False时,
json.dumps()不会进行循环引用的检查。这可以提高序列化的性能,但代价是在对象中存在循环引用时可能会导致无限递归。
import json
# 创建一个包含循环引用的字典
data = {}
data['self'] = data
try:
# 默认情况下,check_circular=True,会抛出ValueError:Circular reference detected(检测到循环引用)
json.dumps(data)
except ValueError as e:
print("ValueError:", e)
try:
# 设置check_circular=False,不会抛出ValueError,
# 但会抛出RecursionError:maximum recursion depth exceeded while encoding a JSON object
# 翻译成中文是RecursionError:在对JSON对象进行编码时超过了最大递归深度。
json.dumps(data, check_circular=False)
except RecursionError as e:
print("RecursionError:", e)
这个例子中,第一个json.dumps()
调用会抛出ValueError,因为默认check_circular为True,检测到了循环引用。
第二个调用尝试通过设置check_circular=False来避免ValueError,但由于存在循环引用,最终会抛出RecursionError。
运行结果
ValueError: Circular reference detected
RecursionError: maximum recursion depth exceeded while encoding a JSON object
allow_nan 参数
默认为True。设置为True(默认值)时,
json.dumps()允许将NaN(Not a Number)、Infinity和-Infinity这样的特殊浮点数值序列化为它们的字符串表示形式。这与JavaScript的JSON相兼容,因为JavaScript的JSON解析器能够理解这些值。设置为False时,如果尝试序列化NaN、Infinity或-Infinity,
json.dumps()将抛出ValueError异常。
import json
data = {
'normal_number': 3.14,
'nan': float('nan'),
'infinity': float('inf'),
'negative_infinity': -float('inf')
}
# 默认情况下,allow_nan=True,特殊浮点数值被允许
print(json.dumps(data))
try:
# 设置allow_nan=False,将抛出ValueError:Out of range float values are not JSON compliant(超出范围的浮点数值不符合JSON标准)
json.dumps(data, allow_nan=False)
except ValueError as e:
print("ValueError:", e)
运行结果
{"normal_number": 3.14, "nan": NaN, "infinity": Infinity, "negative_infinity": -Infinity}
ValueError: Out of range float values are not JSON compliant: nan
在第一个输出中,特殊浮点数值被序列化为它们的字符串表示形式。在第二个尝试中,由于设置了allow_nan=False,尝试序列化包含NaN、Infinity或-Infinity的data字典将抛出ValueError。
cls 参数
默认为Nne。一个可选参数,用于指定一个自定义的JSONEncoder类。如果你提供了这个参数,
json.dumps()会使用这个类来编码对象。
import json
from datetime import datetime
# 创建一个包含datetime对象的字典
data = {
'name': 'Alice',
'created_at': datetime.now()
}
try:
# 默认情况下,`json.dumps()`无法序列化datetime对象,
# 将抛出ValueError:Object of type datetime is not JSON serializable
# 翻译成中文:ValueError:日期时间类型的数据无法被序列化为JSON
json_data = json.dumps(data)
except TypeError as e:
print("ValueError:", e)
# 自定义JSONEncoder类
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat() # 将datetime对象序列化为ISO格式的字符串
return json.JSONEncoder.default(self, obj)
# 使用自定义的JSONEncoder类来序列化datetime对象
json_data = json.dumps(data, cls=CustomEncoder)
print(json_data)
使用cls参数时,你需要定义一个继承自json.JSONEncoder的类,并重写一些方法来实现自定义的序列化逻辑。
在这个例子中,CustomEncoder类重写了default()方法,以支持datetime对象的序列化。
当json.dumps()
被调用并传入CustomEncoder参数,它将使用了CustomEncoder来将datetime对象转换为ISO格式的字符串,从而使得整个字典可以被成功序列化。
运行结果
ValueError: Object of type datetime is not JSON serializable
{"name": "Alice", "created_at": "2024-08-26T17:28:42.466506"}
indent 参数
默认为None。一个可选参数,用于指定每个层级的缩进空格数。如果设置为非负整数,则序列化后的JSON数据将被格式化以便于阅读,每个层级的缩进为指定的空格数。如果设置为None(默认值),则输出的JSON数据将尽可能紧凑,没有额外的空格或换行符。
import json
# 创建一个嵌套的字典
data = {
'name': 'JZY',
'age': 18,
'is_student': False,
'courses': ['1', 2, '3'],
'address': {
'street': 'JZY',
'city': 'JZY',
'zip': '12345'
}
}
# 使用indent参数进行美化输出
pretty_json = json.dumps(data, indent=4)
print(pretty_json)
运行结果
{
"name": "JZY",
"age": 18,
"is_student": false,
"courses": [
"1",
2,
"3"
],
"address": {
"street": "JZY",
"city": "JZY",
"zip": "12345"
}
}
在这个例子中,通过设置indent=4,输出的JSON数据具有4个空格的缩进,使得数据结构更加清晰。 这种格式化的输出在编写和调试代码时非常有用,尤其是在处理复杂的数据结构时。然而,这种格式化会增加输出的大小,因此在需要最小化数据传输量的情况下,可能不适用。
separators 参数
默认为None。一个可选参数,它应该是一个包含两个字符串的元组:第一个用于字段之间的分隔符(默认是,),第二个用于字段与值之间的分隔符(默认是:)。默认情况下,
json.dumps()使用的分隔符是(", ", ": "),这意味着字段之间和字段与值之间会有一个空格。
通过自定义separators,你可以生成没有额外空格的JSON数据,这在需要最小化数据大小的场景下非常有用。
import json
data = {
'name': 'JZY',
'age': 18,
'is_student': False
}
# 使用默认的分隔符(带空格)
default_json = json.dumps(data)
print(default_json)
# 使用自定义的分隔符(无空格)
compact_json = json.dumps(data, separators=(",", ":"))
print(compact_json)
运行结果
{"name": "JZY", "age": 18, "is_student": false}
{"name":"JZY","age":18,"is_student":false}
在第一个输出中,使用了默认的分隔符,字段之间和字段与值之间都有一个空格。在第二个输出中,通过设置separators=(",", “:"),生成了更紧凑的JSON数据,没有额外的空格。
default 参数
默认为None。一个可选参数,接受一个函数。当
json.dumps()遇到无法直接序列化的对象时(例如,自定义对象、datetime对象等),它会调用这个函数来获取一个可序列化的替代值。
import json
from datetime import datetime
# 定义一个自定义的序列化函数,函数检查传入的对象是否为datetime类型,并将其转换为ISO格式的字符串。
# 如果对象不是datetime类型,且没有其他方式可以序列化,函数将抛出TypeError异常。
def default_serializer(obj):
if isinstance(obj, datetime):
return obj.isoformat() # 将datetime对象转换为ISO格式的字符串
raise TypeError(f"Type {type(obj)} not serializable")
# 创建一个包含datetime对象的字典
data = {
'name': 'Alice',
'created_at': datetime.now()
}
# 使用default参数指定自定义的序列化函数
json_data = json.dumps(data, default=default_serializer)
print(json_data)
{"name": "Alice", "created_at": "2024-08-27T09:35:19.642028"}
在这个例子中,default_serializer函数检查传入的对象是否为datetime类型,并将其转换为ISO格式的字符串。如果对象不是datetime类型,且没有其他方式可以序列化,函数将抛出TypeError异常。
当然你也可以在default_serializer函数中自定义一个解码器将那些无法直接序列化的Python对象转换为JSON格式。
sort_keys 参数
默认为False。设置为True时,序列化后的JSON数据中的键将按照字典序(通常是字母序或数字序)进行排序。
设置为False(默认值)时,键将按照它们在Python字典中出现的顺序进行序列化。从Python 3.7开始,字典是有序的,这意味着在同一个Python程序中序列化同一个字典对象将产生一致的结果。
import json
# 创建一个字典,键的顺序可能不是字典序
data = {
'name': 'JZY',
'created_at': '2024-08-27T12:00:00',
'age': 18,
'is_student': False
}
# 不使用sort_keys参数(默认为False),保持键的原始顺序
json_data_unsorted = json.dumps(data)
print(json_data_unsorted)
# 使用sort_keys参数进行排序
json_data_sorted = json.dumps(data, sort_keys=True)
print(json_data_sorted)
运行结果
{"name": "JZY", "created_at": "2024-08-27T12:00:00", "age": 18, "is_student": false}
{"age": 18, "created_at": "2024-08-27T12:00:00", "is_student": false, "name": "JZY"}
在第一个输出中,键的顺序是根据它们在字典中出现的顺序进行序列化的。在第二个输出中,通过设置sort_keys=True,键被按照字典序排序
请求中使用json.dumps()
首先安装requests库。
from datetime import datetime
import requests
import json
# 自定义JSONEncoder类
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat() # 将datetime对象序列化为ISO格式的字符串
return json.JSONEncoder.default(self, obj)
# 定义请求的URL
url = 'http://example.com/api'
# 定义请求体的数据
data = {
'key1': 'value1',
'date': datetime.now()
}
# 将字典转换为JSON格式
json_data = json.dumps(data, cls=CustomEncoder)
# 发送POST请求,headers中指定了请求体的格式为application/json
response = requests.post(url, headers={'Content-Type': 'application/json'}, data=json_data)
# 打印响应的内容
print(response.text)
使用requests.post(url, json=data)
发送请求时, json=data
会自动将数据转换为 JSON 格式,并设置正确的Content-Type 头部(application/json)
,但不会转换date格式的数据。
所以需要使用json.dumps()
转换date为字符串,并使用response = requests.post(url, headers={'Content-Type': 'application/json'}, data=json_data)
发送请求。
json.dump() 方法
json.dumps()
能够 Python 对象序列化为 JSON 格式的字符串,并将这个字符串写入到一个文件中。
它接受至少两个参数,第一个参数是要序列化的 Python 对象,第二个参数是一个文件对象,这个文件对象应该已经处于写入模式(‘w’ 或 ‘wb’)。
json.dump()
方法的基本用法:
json.dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, encoding="utf-8", default=None, sort_keys=False)
json.dump()
的各个参数中,obj和fp是必选的,其他参数可选。json.dump()
和json.dumps()
的唯一区别是json.dump()
是将数据写进文件内,多了fp参数。
对于其他参数,json.dump()
和json.dump()
的用法是一样的,不再赘述。
import json
# 假设我们有一个字典
data = {
'name': 'JZY',
'age': 18,
'address': 'HeNan'
}
# 将数据写入到到py文件当前目录下的data.json文件中
# 如果data.json不存在,自动创建
with open('data.json', 'w') as f:
json.dump(data, f)
运行结果

这个方法非常适合于将数据持久化存储到文件,或者通过网络发送到其他服务。
THEEND

© 转载需要保留原始链接,未经明确许可,禁止商业使用。CC BY-NC-ND 4.0
...