跳至内容
快速上手 json 库

快速上手 json 库

2024年08月25日·竹子是不秋草
竹子是不秋草

Python 内置的 Json 库可以将 Json 对象与 Python 字典相互转换,是一个轻量、好用的库。

json 到 python

提供两种方法:json.loads() 用于将字符串格式的 Json 对象转换为 Python 对象;json.load() 用于将类文件对象(比如 .json 格式文件)的 Json 对象转换为 Python 对象。

json 类型转换到 python 的类型对照表:

JSON数据类型 语法示例 Python 解码后对应的类型 补充说明
对象(Object) {“name”: “张三”, “age”: 25} dict(字典) JSON 核心复合类型,键只能是字符串
数组(Array) [1, “test”, true, null] list(列表) 有序集合,可嵌套任意 JSON 类型
字符串(String) “hello”, “2026-03-23” str(字符串) 支持 Unicode,需用双引号包裹
数字(Number) 123, 3.14, -45, 1e5 int/float(整数 / 浮点数) JSON 无区分整数 / 浮点数,Python 自动适配
布尔值(Boolean) true, false bool(True/False) 注意 JSON 是小写,Python 是大写
空值(Null) null None(NoneType) JSON 唯一的空值类型

基本用法:

import json

# 定义一个json格式的字符串
json_data = '{"Name": "JZY", "age": 18, "address": ["HangZhou", "XiHuQu"]}'

# 转换成 python 对象
dict_data = json.loads(json_data)

print(json_data, type(json_data))  # 打印{"Name": "JZY", "age": 18, "address": ["HangZhou", "XiHuQu"]} <class 'str'>
print(dict_data, type(dict_data))  # {'Name': 'JZY', 'age': 18, 'address': ['HangZhou', 'XiHuQu']} <class 'dict'>
print(dict_data["address"], type(dict_data["address"]))  # ['HangZhou', 'XiHuQu'] <class 'list'>


# 假设目录下有 data.json 文件且内容如:'{"Name": "JZY", "age": 18, "address": ["HangZhou", "XiHuQu"]}'
with open('data.json', 'r', encoding='utf-8') as f:
    data = json.load(f, parse_float=Decimal)

print(json_data, type(json_data))  # 打印{"Name": "JZY", "age": 18, "address": ["HangZhou", "XiHuQu"]} <class 'str'>
print(dict_data, type(dict_data))  # {'Name': 'JZY', 'age': 18, 'address': ['HangZhou', 'XiHuQu']} <class 'dict'>
print(dict_data["address"], type(dict_data["address"]))  # ['HangZhou', 'XiHuQu'] <class 'list'>

自定义解码

Json 库支持多种用于自定义解码逻辑的参数,而且还可以通过它扩展对其他类型数据的支持。

parse_floatparse_intparse_constant 用于自定义整数、浮点数和特殊常量(NaN/Infinity/-Infinity)的解析。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import json
from decimal import Decimal # 通过Decimal转为高精数

json_string = """{
    "int": 123,
    "float": 3.123453435,
    "nan": NaN,
    "inf": Infinity,
    "ninf": -Infinity
    }"""

# 自定义整数解码逻辑,比如设置最大值
def parse_int_limit(s: str):
    num = int(s)
    if num > 100:
        num = 100
    return num

# 自定义特殊常量解析函数
def custom_constant(s: str):
    """
    处理JSON中的特殊常量:
    - NaN → None
    - Infinity → 1000000(自定义最大值)
    - -Infinity → -1000000(自定义最小值)
    """
    if s == "NaN":
        return None
    elif s == "Infinity":
        return 1000000
    elif s == "-Infinity":
        return -1000000
    else:
        return s



data = json.loads(json_string, parse_int = parse_int_limit,parse_float = Decimal,parse_constant=custom_constant)

print(data) # 打印{'int': 100, 'float': Decimal('3.123453435'), 'nan1': None, 'inf': 1000000, 'ninf': -1000000}

还有 object_pairs_hookobject_hookcls 三个参数可用自定义编码,首先需要知道它们之间的优先级。

    flowchart TD
    A[开始解析JSON对象] --> B{是否指定 cls?}
    B -- 是 --> C[使用自定义 JSONDecoder<br>(完全接管解码逻辑)]
    B -- 否 --> D{是否指定 object_pairs_hook?}
    D -- 是 --> E[调用 object_pairs_hook<br>(传入键值对列表)]
    D -- 否 --> F{是否指定 object_hook?}
    F -- 是 --> G[调用 object_hook<br>(传入已构建字典)]
    F -- 否 --> H[返回普通 dict]
    C --> I[解码结束]
    E --> I
    G --> I
    H --> I
  

参数 object_hook 指定的函数于字典构建(重复键自动去除)完成后被调用,可以返回任何类型以代替字典。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import json
from datetime import datetime

json_string = '{"name": "JZY", "name": "JZY", "date": "2024-08-27T12:00:00"}'

def str_datetime(pairs):
    print(pairs) # 打印 {"name": "JZY", "date": "2024-08-27T12:00:00"}
    if 'date' in pairs:
        pairs['date'] = datetime.fromisoformat(pairs['date'].replace("'", ""))
    return pairs


data = json.loads(json_string)
print(data, type(data["date"]))  # 打印{'name': 'JZY', 'date': '2024-08-27T12:00:00'} <class 'str'>

# 使用自定义的解码器
data = json.loads(json_string, object_hook=str_datetime)
print(data, type(data["date"])) # 打印{'name': 'JZY', 'date': datetime.datetime(2024, 8, 27, 12, 0)} <class 'datetime.datetime'>
    

参数 object_pairs_hook 指定的函数于字典构建(保留重复键)前被调用,可以返回任何类型以代替字典。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import json
from datetime import datetime

json_string = '{"name": "JZY", "name": "JZY", "date": "2024-08-27T12:00:00"}'

def str_datetime(pairs):
    print(pairs) # 打印 [('name', 'JZY'), ('name', 'JZY'), ('date', '2024-08-27T12:00:00')]
    res = {}
    for k, v in pairs:
        if k == "date":
            v = datetime.fromisoformat(v.replace("'", ""))
        if k in res:
            res[k].append(v)
        else:
            res[k] = [v]
    return res


data = json.loads(json_string)
print(data, type(data["date"]))  # 打印{'name': 'JZY', 'date': '2024-08-27T12:00:00'} <class 'str'>

# # 使用自定义的解码器
data = json.loads(json_string, object_pairs_hook=str_datetime)
print(data, type(data["date"][0])) # 打印{'name': 'JZY', 'date': datetime.datetime(2024, 8, 27, 12, 0)} <class 'datetime.datetime'>
    

参数 cls 说是可以深度定制解码逻辑,我几乎没有用过,或许读者也用不到。这里就不介绍了,有兴趣的读者可以自行搜索用法(万能的AI)。

python 到 json

提供两种方法:json.dumps() 用于将 Python 对象转换为字符串格式的 Json 对象;json.dump() 用于将 Python 对象转换为 JSON 格式的字符串,并写入类文件对象(比如 .json 格式文件)。

python 类型转换到 json 的类型对照表:

JSON数据类型 语法示例 Python 解码后对应的类型 补充说明
dict(字典) {“name”: “张三”, “age”: 25} 对象(Object) JSON 核心复合类型,键只能是字符串
list(列表)、tuple(元组) [1, “test”, true, null]、(1,“2”) 数组(Array) 有序集合,可嵌套任意 JSON 类型
str(字符串) “hello”, “2026-03-23” 字符串(String) 支持 Unicode,需用双引号包裹
int/float(整数 / 浮点数) 123, 3.14, -45, 1e5 数字(Number) JSON 无区分整数
bool(True/False) true, false 布尔值(Boolean) 注意 JSON 是小写,Python 是大写
None(NoneType) null 空值(Null) JSON 唯一的空值类型

基本用法:

import json

# 定义一个json格式的字符串
json_data = {"Name": "JZY", "age": 18, "address": ["HangZhou", "XiHuQu"]}

# 转换成 JSON 格式的字符串
dict_data = json.dumps(json_data)

print(json_data, type(json_data))  # 打印{"Name": "JZY", "age": 18, "address": ["HangZhou", "XiHuQu"]} <class 'str'>
print(dict_data, type(dict_data))  # {'Name': 'JZY', 'age': 18, 'address': ['HangZhou', 'XiHuQu']} <class 'dict'>


# 如果目录下有 data.json 文件,文件中会写入数据
with open('data.json', 'w', encoding='utf-8') as f:  
    json.dump(json_data, f)

自定义编码

参数 default 可以接受一个函数,用于序列化不支持的 Python 对象(自定义对象、datetime对象等)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import json
from datetime import datetime

def default_serializer(obj):
    print('已调用 default_serializer')
    return obj.isoformat()  # 将datetime对象转换为ISO格式的字符串


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

json_data = json.dumps(data1, default=default_serializer)
print(json_data) # 输出:{"name": "Alice", "created_at": "2025-04-08T13:36:07.490765"}

当然还可以通过参数 cls 深度定制编码逻辑,但这里就不介绍了,有兴趣的读者可以自行搜索用法。

非法键处理

如果遇到字典中的键不是基本类型(非str, unicode, int, long, float, bool, None),设置为 True,则跳过该键值对不进行序列化,而不抛出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) # 输出 "TypeError: keys must be str, int, float, bool or None, not tuple"

# 使用 skipkeys=True 不会抛出错误,但会丢失那些无法序列化的键值对。
json_data = json.dumps(data, skipkeys=True)
print(json_data)  # 输出 "{"a": 1, "d": 3}"

字符转义 ASCII

参数 ensure_ascii 设置为 True(默认值)时,非 ASCII 字符会被转义成 ASCII 字符。这确保了最大兼容性,因为 ASCII 是所有 Unicode 字符集的子集。设置为 False 时,会尽可能地输出原始字符。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import json

# ü非ASCII字符,汉字非ASCII字符。
data = {
    'name': 'Günter',
    'city': '北京'
}

print(json.dumps(data)) # 输出:{"name": "G\u00fcnter", "city": "\u5317\u4eac"}
print(json.dumps(data, ensure_ascii=False)) # 输出:{"name": "Günter", "city": "北京"}

循环引用检查

参数 check_circular 设置为 True(默认值),会检查对象中是否存在循环引用,即对象直接或间接地引用自己。如果发现循环引用,将抛出ValueError异常。设置为 False 时,不会进行循环引用的检查,这可以提高序列化的性能,但代价是在对象中存在循环引用时可能会导致无限递归。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import json

# 创建一个包含循环引用的字典
data = {}
data['self'] = data

try:
    json.dumps(data) 
except ValueError as e:
    print("ValueError:", e) # 输出:ValueError: Circular reference detected

格式化输出

参数 indent (默认为 None)可以将序列化后的 JSON 数据格式化以便于阅读,缩进为指定值。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import json

data = {
    'name': 'ZLH',
    'age': 18,
    'is_student': False,
    'courses': ['1', 2, '3'],
    'address': {
        'street': 'JZY',
        'city': 'JZY',
        'zip': '12345'
    }
}

pretty_json = json.dumps(data) # 输出:{"name": "ZLH", "age": 18, "is_student": false, "courses": ["1", 2, "3"], "address": {"street": "JZY", "city": "JZY", "zip": "12345"}}
print(pretty_json)

pretty_json = json.dumps(data, indent=4)
print(pretty_json)
# 输出:
# {
#     "name": "ZLH",
#     "age": 18,
#     "is_student": false,
#     "courses": [
#         "1",
#         2,
#         "3"
#     ],
#     "address": {
#         "street": "JZY",
#         "city": "JZY",
#         "zip": "12345"
#     }
# }

参考

json — JSON 编码器和解码器

最后更新于