orjson 是一个号称 "Fast, correct JSON library for Python" 的第三方库,它最大的卖点就是快——根据官方基准测试,它的序列化速度是标准库 json 的 10 倍以上,反序列化速度也快 2 倍以上。
它不仅仅追求速度,在正确性上也更为严格,并且原生支持很多让标准库 json 头疼的数据类型,比如 dataclass、datetime、numpy 数组和 UUID。
快速上手:安装与基础用法
首先,使用 pip 安装它:
使用起来和标准库很像,但有一个关键区别:orjson.dumps() 返回的是 bytes 对象,而不是 str。这一设计主要是为了追求更高的性能,因为它在底层直接处理 UTF-8 编码的字节。
import orjson# 一个包含多种数据类型的示例数据data = { "name": "Alice", "age": 30, "is_active": True, "tags": ["developer", "python", "orjson"], "score": None}# 序列化:Python 对象 -> JSON (bytes)json_bytes = orjson.dumps(data)print(json_bytes)# 输出: b'{"name":"Alice","age":30,"is_active":true,"tags":["developer","python","orjson"],"score":null}'# 注意,它输出的是 bytes,如果想得到字符串,需要 decodejson_str = json_bytes.decode('utf-8')print(json_str)# 输出: {"name":"Alice","age":30,"is_active":true,"tags":["developer","python","orjson"],"score":null}# 反序列化:JSON (bytes 或 str) -> Python 对象original_data = orjson.loads(json_bytes)print(original_data)# 输出: {'name': 'Alice', 'age': 30, 'is_active': True, 'tags': ['developer', 'python', 'orjson'], 'score': None}
核心优势:原生支持复杂类型
这是 orjson 最吸引人的地方。标准库 json 在处理 datetime 或 dataclass 时会直接报错,而 orjson 可以轻松应对。
import orjsonfrom dataclasses import dataclassfrom datetime import datetimeimport uuid@dataclassclass User: id: int name: str# 一个包含 orjson 原生支持类型的复杂对象complex_data = { "user": User(id=1, name="Bob"), "created_at": datetime.now(), "unique_id": uuid.uuid4()}# 直接序列化,无需额外配置!json_bytes = orjson.dumps(complex_data)print(json_bytes)# 输出类似: b'{"user":{"id":1,"name":"Bob"},"created_at":"2024-05-20T12:34:56.789012","unique_id":"123e4567-e89b-12d3-a456-426614174000"}'
定制输出:使用 option 参数
orjson 通过 option 参数提供了许多标志位来微调输出结果,多个选项可以用 | (按位或) 组合使用。
1. 美化输出 (OPT_INDENT_2)
虽然 orjson 没有 indent 参数,但提供了 OPT_INDENT_2 来获得格式化的、带缩进的输出。
data = {"a": 1, "b": {"c": 2, "d": [3, 4]}}# 紧凑输出print(orjson.dumps(data))# b'{"a":1,"b":{"c":2,"d":[3,4]}}'# 美化输出pretty_bytes = orjson.dumps(data, option=orjson.OPT_INDENT_2)print(pretty_bytes.decode())# {# "a": 1,# "b": {# "c": 2,# "d": [# 3,# 4# ]# }# }
2. 处理非字符串键 (OPT_NON_STR_KEYS)
标准 JSON 要求字典的键必须是字符串。当你的字典键是整数或其他类型时,orjson 默认会报错。通过 OPT_NON_STR_KEYS 可以让它自动转换为字符串。
data = {1: "one", 2: "two"}# 默认行为会报错: orjson.JSONEncodeError: Key is not a string# orjson.dumps(data)# 启用选项,将键转换为字符串json_bytes = orjson.dumps(data, option=orjson.OPT_NON_STR_KEYS)print(json_bytes)# b'{"1":"one","2":"two"}'
3. 对键进行排序 (OPT_SORT_KEYS)
如果你需要输出的 JSON 字段按照键名排序,可以使用 OPT_SORT_KEYS。
data = {"name": "Alice", "age": 30, "city": "New York"}json_bytes = orjson.dumps(data, option=orjson.OPT_SORT_KEYS)print(json_bytes)# b'{"age":30,"city":"New York","name":"Alice"}'
4. 省略微秒 (OPT_OMIT_MICROSECONDS)
在处理 datetime 对象时,有时你可能不需要微秒部分。
from datetime import datetimedata = {"timestamp": datetime.now()}# 默认包含微秒print(orjson.dumps(data))# b'{"timestamp":"2024-05-20T12:34:56.789012"}'# 省略微秒print(orjson.dumps(data, option=orjson.OPT_OMIT_MICROSECONDS))# b'{"timestamp":"2024-05-20T12:34:56"}'
5. 序列化 NumPy 数组 (OPT_SERIALIZE_NUMPY)
对于数据科学和机器学习领域的开发者来说,这个功能非常实用。orjson 可以高效地将 NumPy 数组序列化为 JSON 数组。
import numpy as npdata = {"array": np.array([[1, 2], [3, 4]])}# 需要加上 OPT_SERIALIZE_NUMPY 选项json_bytes = orjson.dumps(data, option=orjson.OPT_SERIALIZE_NUMPY)print(json_bytes)# b'{"array":[[1,2],[3,4]]}'
扩展能力:使用 default 函数处理自定义类型
对于 orjson 无法原生处理的类型,你可以像标准库一样,提供一个 default 函数。当 orjson 遇到不认识的对象时,就会调用这个函数,由你决定如何将其转换为 JSON 兼容的类型。
import orjsonimport decimal# 假设有一个自定义类class Person: def __init__(self, name, age): self.name = name self.age = age# 定义一个处理函数def my_default(obj): # 处理 Person 对象 if isinstance(obj, Person): return {"name": obj.name, "age": obj.age} # 处理 Decimal 对象 if isinstance(obj, decimal.Decimal): return str(obj) # 如果都无法处理,必须抛出异常,否则会被序列化为 null raise TypeError(f"Object of type {type(obj).__name__} is not JSON serializable")# 测试数据test_data = { "person": Person("Charlie", 28), "price": decimal.Decimal("99.99")}# 使用 default 函数json_bytes = orjson.dumps(test_data, default=my_default)print(json_bytes)# b'{"person":{"name":"Charlie","age":28},"price":"99.99"}'
性能与注意事项
速度至上:orjson 的性能优势在处理大规模数据时尤其明显。它的核心是用 Rust 编写的,确保了极高的效率。
返回 bytes:这是最需要注意的一点。如果你需要字符串,请手动调用 .decode()。
没有 dump 和 load:orjson 专注于核心的序列化/反序列化功能,不提供直接读写文件对象的 dump() 和 load() 函数。你需要自己处理文件的打开和写入。
严格的 JSON 规范:orjson 遵循严格的 JSON 规范,例如,它不支持 NaN 或 Infinity,遇到这些值会报错。