最佳实践
下面给你一份 「Python orjson 最佳实践(全套设计)」,涵盖:
- 为什么用 orjson
- orjson dumps/loads 最佳封装
- Pydantic / FastAPI 集成方式
- Datetime 处理方案
- 类型标注最佳实践
- VSCode/Pylance 误报解决
- 完整 utils.orjson_utils 模块
适用于生产环境(FastAPI + Python 3.12)。
orjson 的优势:
- C 编写,速度是 json/ujson/rapidjson 中最快
- dumps 返回 bytes 而不是 str(避免重复编码)
- 内置支持 datetime -> RFC3339(ISO 8601)
- 准确、高效、安全
适合:
- 高性能 API
- 高频 JSON 序列化
- 大量数据序列化
你的项目中不应该直接调用 orjson.dumps()。
👇 官方推荐 + 生产环境最优设计
utils/orjson_utils.py
# utils/orjson_utils.py
from __future__ import annotations
import orjson
from typing import Any
def dumps(obj: Any, *, option: int | None = None) -> str:
"""
安全的 JSON 序列化,返回 str
orjson.dumps -> bytes,因此需要 decode
"""
if option is None:
option = orjson.OPT_NON_STR_KEYS | orjson.OPT_SERIALIZE_NUMPY
return orjson.dumps(obj, option=option).decode("utf-8")
def loads(data: str | bytes) -> Any:
"""反序列化 JSON 字符串/bytes"""
return orjson.loads(data)
使用:
from utils.orjson_utils import dumps, loads
json_str = dumps({"a": 1})
obj = loads(json_str)
orjson 支持 datetime 自动序列化:
import datetime, orjson
orjson.dumps({"t": datetime.datetime.now()})
默认输出 ISO8601:
{"t":"2025-01-01T12:00:00+08:00"}
要格式化为 “YYYY-MM-DD HH:mm:ss” -> 自定义 default 处理器:
def default(obj):
if isinstance(obj, datetime.datetime):
return obj.strftime("%Y-%m-%d %H:%M:%S")
raise TypeError
封装:
def dumps_datetime(obj: Any) -> str:
return orjson.dumps(
obj,
option=orjson.OPT_NON_STR_KEYS,
default=lambda o: o.strftime("%Y-%m-%d %H:%M:%S")
if hasattr(o, "strftime")
else TypeError
).decode()
FastAPI 支持替换 JSON Encoder:
main.py:
from fastapi import FastAPI
from fastapi.responses import ORJSONResponse
app = FastAPI(default_response_class=ORJSONResponse)
⏳ 性能优化:开箱即用。
Pydantic 设置:
from pydantic import BaseModel
from datetime import datetime
class Item(BaseModel):
name: str
created_at: datetime
model_config = {
"ser_json_timedelta": "iso8601",
"ser_json_bytes": "base64",
}
安装类型 stub:
pip install types-orjson
没有类型提示时,VSCode 会报错,这是正常现象。
性能最佳 + 最常用:
ORJSON_OPTIONS = (
orjson.OPT_NON_STR_KEYS |
orjson.OPT_SERIALIZE_NUMPY |
orjson.OPT_UTC_Z |
orjson.OPT_SORT_KEYS
)
其中:
- OPT_NON_STR_KEYS:允许 dict key 为数字/非字符串
- OPT_SERIALIZE_NUMPY:自动序列化 numpy 数据
- OPT_SORT_KEYS:排序键(利于 diff)
- OPT_UTC_Z:UTC 时间加 Z
这些类型需手动转换:
- set
- complex
- Decimal(需要 str 或 float)
- UUID
- bytes(默认支持)
示例:
orjson.dumps({"set": {1,2}}) # TypeError
必须通过 default 处理:
def default(obj):
if isinstance(obj, set):
return list(obj)
raise TypeError
你直接复制即可用:
# utils/orjson_utils.py
from __future__ import annotations
import orjson
from typing import Any
from datetime import datetime, date
ORJSON_OPTIONS = (
orjson.OPT_NON_STR_KEYS |
orjson.OPT_SERIALIZE_NUMPY |
orjson.OPT_SORT_KEYS
)
def _default(obj: Any):
"""自定义 fallback 处理器"""
if isinstance(obj, (datetime, date)):
return obj.strftime("%Y-%m-%d %H:%M:%S") if isinstance(obj, datetime) else obj.strftime("%Y-%m-%d")
if isinstance(obj, set):
return list(obj)
raise TypeError(f"Object of type {type(obj)} is not JSON serializable")
def dumps(obj: Any, *, option: int | None = None) -> str:
"""orjson.dumps 的封装,输出 str"""
if option is None:
option = ORJSON_OPTIONS
return orjson.dumps(obj, option=option, default=_default).decode("utf-8")
def loads(data: str | bytes) -> Any:
"""JSON 反序列化"""
return orjson.loads(data)
from utils.orjson_utils import dumps, loads
print(dumps({"a": 1, "t": datetime.now()}))
FastAPI:
app = FastAPI(default_response_class=ORJSONResponse)