Skip to main content
Documents
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

最佳实践

下面给你一份 「Python orjson 最佳实践(全套设计)」,涵盖:

  • 为什么用 orjson
  • orjson dumps/loads 最佳封装
  • Pydantic / FastAPI 集成方式
  • Datetime 处理方案
  • 类型标注最佳实践
  • VSCode/Pylance 误报解决
  • 完整 utils.orjson_utils 模块

适用于生产环境(FastAPI + Python 3.12)。

✅ 1. 为什么 orjson 是 Python 最快 JSON 库?

orjson 的优势:

  • C 编写,速度是 json/ujson/rapidjson 中最快
  • dumps 返回 bytes 而不是 str(避免重复编码)
  • 内置支持 datetime -> RFC3339(ISO 8601)
  • 准确、高效、安全

适合:

  • 高性能 API
  • 高频 JSON 序列化
  • 大量数据序列化

✅ 2. ★ 最佳实践:统一封装 dumps/loads

你的项目中不应该直接调用 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)

✅ 3. ★ datetime 最佳处理方式

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()

✅ 4. ★ 与 FastAPI 集成(最推荐的写法)

FastAPI 支持替换 JSON Encoder:

main.py:

from fastapi import FastAPI
from fastapi.responses import ORJSONResponse

app = FastAPI(default_response_class=ORJSONResponse)

⏳ 性能优化:开箱即用。

🔥 FastAPI 模型里优雅序列化 datetime

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",
    }

✅ 5. 解决 VSCode “Module ‘orjson’ has no member dumps” 误报

安装类型 stub:

pip install types-orjson

没有类型提示时,VSCode 会报错,这是正常现象。

✅ 6. ★ orjson 最佳 option 组合

性能最佳 + 最常用:

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

✅ 7. orjson 不支持的类型(必须注意)

这些类型需手动转换:

  • 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

✅ 8. 完整 utils/orjson_utils.py(最佳实践标准版)

你直接复制即可用:

# 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)