Json是是一种轻量级的数据交换格式,易于人阅读和编写,现在大多服务的接口数据都使用Json进行传递。测试人员与Json免不了打交道。

Python官方提供了Json库供用户处理Json数据,包括4种方法:

  • dumps()
  • loads()
  • dump()
  • load()

这4种方法基本可以满足测试人员的需求。如果有性能更好、功能更多的需求,可以使用第三方库,如orjson、rapidjson、Pydantic。

本篇详细介绍如何使用 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(obj, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False)

各个参数中,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

设置为 True 时,如果遇到字典中的键不是基本类型(非str, unicode, int, long, float, bool, None),则跳过该键值对不进行序列化,而不是抛出TypeError异常。

设置为 False(默认值),如果字典中包含非基本类型的键,则抛出 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}

参数 ensure_ascii

设置为 True(默认值)时,所有的非 ASCII 字符(即Unicode字符)都会被转义成ASCII字符。这意味着输出的JSON字符串将只包含ASCII字符,这确保了最大兼容性,因为 ASCII 是所有 Unicode 字符集的子集。

设置为 False 时,会尽可能地输出原始的 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": "北京"}

参数 check_circular

设置为 True(默认值),会检查对象中是否存在循环引用,即对象直接或间接地引用自己。如果发现循环引用,将抛出ValueError异常。

设置为 False 时,不会进行循环引用的检查。这可以提高序列化的性能,但代价是在对象中存在循环引用时可能会导致无限递归。

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)

运行结果

ValueError: Circular reference detected
RecursionError: maximum recursion depth exceeded while encoding a JSON object

参数 allow_nan

设置为 True(默认值)时,允许将 NaN(Not a Number)、Infinity 和 -Infinity 这样的特殊浮点数值序列化为它们的字符串表示形式。这与JavaScript的JSON相兼容,因为JavaScript的JSON解析器能够理解这些值。

设置为False时,如果序列化 NaN、Infinity 或 -Infinity,将抛出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

参数 cls

默认为 None,用于指定一个自定义的 JSONEncoder 类。如果你提供了这个参数,会使用这个类来编码对象。

import json
from datetime import datetime

# 创建一个包含datetime对象的字典
data = {
    'name': 'Alice',
    'created_at': datetime.now()
}


try:
    # 默认情况下,无法序列化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 对象的序列化。 当传入CustomEncoder 参数,将使用了 CustomEncoder 的 default()方法来将 datetime 对象转换为ISO格式的字符串,从而使得整个字典可以被成功序列化。

运行结果

ValueError: Object of type datetime is not JSON serializable
{"name": "Alice", "created_at": "2024-08-26T17:28:42.466506"}

参数 indent

默认为 None,用于指定每个层级的缩进空格数,此时输出的JSON数据将尽可能紧凑,没有额外的空格或换行符。

如果设置为非负整数,则序列化后的JSON数据将被格式化以便于阅读,每个层级的缩进为指定的空格数。

import json

# 创建一个嵌套的字典
data = {
    'name': 'JZY',
    'age': 18,
    'is_student': False,
    'courses': ['1', 2, '3'],
    'address': {
        'street': 'JZY',
        'city': 'JZY',
        'zip': '12345'
    }
}

# 默认输出
print('默认输出:')
pretty_json = json.dumps(data)
print(pretty_json)

# 使用indent参数进行美化输出
print('美化输出:')
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"}}
美化输出
{
    "name": "JZY",
    "age": 18,
    "is_student": false,
    "courses": [
        "1",
        2,
        "3"
    ],
    "address": {
        "street": "JZY",
        "city": "JZY",
        "zip": "12345"
    }
}

参数 separators

默认为 None,此时使用的分隔符是 (", “, “: “),这意味着字段之间和字段与值之间会有一个空格。

你可以自定义分隔符,它应该是一个包含两个字符串的元组。比如自定义为 (”,”, “:"),去掉空格。

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}

参数 default

默认为 None。

接受一个函数,当遇到无法直接序列化的对象时(自定义对象、datetime对象等),它会调用这个函数来获取一个可序列化的替代值。

import json
from datetime import datetime


# 定义一个自定义的序列化函数,函数检查传入的对象是否为datetime类型,并将其转换为ISO格式的字符串。
# 如果对象不是datetime类型,且没有其他方式可以序列化,函数将抛出TypeError异常。
def default_serializer(obj):
    print('已调用 default_serializer')
    return obj.isoformat()  # 将datetime对象转换为ISO格式的字符串


# 创建一个包含datetime对象的字典
data1 = {
    'name': 'Alice',
    'created_at': datetime.now()
}

# 创建一个不包含datetime对象的字典
data2 = {
    'name': 'Alice',
    'age': 13
}


# 序列化 data1,因为data1里有无法序列化的对象,会调用 default_serializer 函数
print('序列化 data1')
json_data = json.dumps(data1, default=default_serializer)
print(json_data)

# 序列化 data2,因为data1里没有无法序列化的对象,不会调用 default_serializer 函数
print('序列化 data2')
json_data = json.dumps(data2, default=default_serializer)
print(json_data)

运行结果

序列化 data1
已调用 default_serializer
{"name": "Alice", "created_at": "2025-05-29T10:33:55.463019"}
序列化 data2
{"name": "Alice", "age": 13}

参数 sort_keys

设置为True时,序列化后的JSON数据中的键将按照字典序(通常是字母序或数字序)进行排序。从Python 3.7开始,字典是有序的,这意味着在同一个Python程序中序列化同一个字典对象将产生一致的结果。

设置为False(默认值)时,将按照它们在Python字典中出现的顺序进行序列化。

import json

# 创建一个字典,键的顺序可能不是字典序
data = {
    'name': 'JZY',
    'created_at': '2024-08-27T12:00:00',
    'age': 18,
    'is_student': False
}

# 不使用 字典序(默认为False),保持键的原始顺序
json_data_unsorted = json.dumps(data)
print(json_data_unsorted)

# 使用字典序进行排序
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"}

请求中使用dumps()示例

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)

json.dump() 方法

能够 Python 对象序列化为 JSON 格式的字符串,并将这个字符串写入到一个文件中。

它接受至少两个参数,第一个参数是要序列化的 Python 对象,第二个参数是一个文件对象,这个文件对象应该已经处于写入模式(‘w’ 或 ‘wb’)。

基本用法:

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)

各个参数中,obj和fp是必选的,其他参数可选。dump() 和 dumps() 的区别是 dump() 是将数据写进文件内,多了fp参数。 对于其他参数,两者的用法是一样的。

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