JSON Formatter Python — json.dumps() 指南

·Backend Developer·审阅者Dmitri Volkov·发布日期

直接在浏览器中使用免费的 JSON格式化工具,无需安装。

在线试用 JSON格式化工具 →

当我调试 Python API 客户端时,第一个想到的就是 Python pretty print JSON——只需一行 json.dumps(data, indent=4), 原本难以阅读的单行数据就变得清晰易读。Python 内置的 json 模块在标准库中即可完成全部工作,无需安装第三方包。 如果只需要快速格式化而无需编写代码,ToolDeck 的 JSON 格式化工具 可立即完成。本指南涵盖所有实用方法: 带完整参数说明的 json.dumps()pprint、 用于高性能格式化的 orjsonjson.tool CLI, 以及格式化 API 响应、从磁盘读取文件等真实场景——所有代码均兼容 Python 3.8+。 同时还涵盖序列化 datetime UUID 等自定义类型、使用 ijson 流式处理 GB 级文件,以及使用 rich 在终端实现语法高亮。

核心要点
  • json.dumps(data, indent=4) 自 Python 2.6 起内置于标准库——无需安装。
  • 当数据包含汉字、带重音字母或 emoji 时,请传入 ensure_ascii=False
  • 对于 datetimeUUID 或自定义类,使用 default= 参数或子类化 json.JSONEncoder
  • separators=(',', ':') 去除所有空白符——适用于网络传输或 URL 嵌入。
  • orjson 比标准库快 5–10 倍,并原生支持 datetimeuuid.UUID
  • pprint.pprint() 输出 Python 语法(True/None),而非有效 JSON——绝不用于文件或 API 响应。
  • 对于超过 50 MB 的 JSON 文件,请用 ijson 流式处理,避免使用 json.load() 导致 MemoryError

什么是 JSON 格式化输出?

格式化输出(Pretty Printing)将密集压缩的 JSON 字符串转换为具有一致缩进和换行的 人类可读格式。这种转换纯属外观上的变化:数据完全相同,只是呈现方式不同。Python 的 json 模块在标准库中即可完成全部工作——无需安装任何内容。

Before · json
After · json
{"id":"usr_9f3a2b","name":"李明","roles":["admin","editor"],"prefs":{"theme":"dark","lang":"zh"}}
{
    "id": "usr_9f3a2b",
    "name": "李明",
    "roles": [
        "admin",
        "editor"
    ],
    "prefs": {
        "theme": "dark",
        "lang": "zh"
    }
}

json.dumps() — 格式化 JSON 的标准方式

json.dumps() 自 Python 2.6 起即是标准库的一部分——只需 import json, 无需额外安装。它将任何 JSON 兼容的 Python 对象序列化为格式化字符串。关键参数是 indent: 设为 4(或 2)即可获得可读输出。

Python 3.8+ — 最简示例
import json

user = {
    "id": "usr_9f3a2b",
    "name": "李明",
    "roles": ["admin", "editor"],
    "prefs": {"theme": "dark", "lang": "zh"}
}

print(json.dumps(user, indent=4, ensure_ascii=False))
# 输出:
# {
#     "id": "usr_9f3a2b",
#     "name": "李明",
#     "roles": [
#         "admin",
#         "editor"
#     ],
#     "prefs": {
#         "theme": "dark",
#         "lang": "zh"
#     }
# }

在生产环境中,通常还需要 sort_keys=True (跨运行保持一致输出)和 ensure_ascii=False (保留非 ASCII 字符的可读性):

Python 3.8+ — 使用 sort_keys 和 ensure_ascii
import json

api_response = {
    "timestamp": "2024-05-01T10:30:00Z",
    "status": "success",
    "data": {
        "user_id": "usr_9f3a2b",
        "display_name": "王芳",
        "city": "上海",
        "score": 4892.5,
        "tags": ["python", "backend", "api"]
    }
}

print(json.dumps(api_response, indent=4, sort_keys=True, ensure_ascii=False))
# 输出(键已排序,汉字保留原样):
# {
#     "data": {
#         "city": "上海",
#         "display_name": "王芳",
#         "score": 4892.5,
#         "tags": ["api", "backend", "python"],
#         "user_id": "usr_9f3a2b"
#     },
#     "status": "success",
#     "timestamp": "2024-05-01T10:30:00Z"
# }
注意:json.dumps() 返回字符串。 要将格式化 JSON 直接写入文件,请使用 json.dump(data, f, indent=4)(不带 s)——它直接写入文件对象,避免在内存中创建中间字符串。

json.dumps() 参数参考

除对象本身外,所有参数均为可选。默认值生成紧凑、ASCII 安全的 JSON—— 如需人类可读的输出,请显式传入相应参数。

参数
类型
默认值
说明
obj
any
要序列化为 JSON 格式字符串的 Python 对象。
indent
int | str | None
None
每级缩进的空格数。None = 紧凑单行,0 = 仅换行,4 = 标准。
sort_keys
bool
False
对所有嵌套级别的字典键按字母顺序排序。
ensure_ascii
bool
True
将非 ASCII 字符转义为 \uXXXX。设为 False 可原样保留 Unicode 字符。
separators
tuple | None
None
(item_sep, key_sep) 元组。使用 (",", ":") 可输出无空格的最紧凑 JSON。
default
callable | None
None
对默认无法序列化的类型调用。抛出 TypeError 可拒绝该值。
allow_nan
bool
True
将 float("nan") 和 float("inf") 序列化为 JS 字面量。设为 False 会抛出 ValueError。

使用 separators 参数输出紧凑 JSON

默认情况下,json.dumps() ", " 分隔项目,用 ": " 分隔键值。separators 参数可覆盖这两者。传入 (',', ':') 可去除所有空白符,生成最紧凑的有效 JSON——适用于网络传输、URL 嵌入或存储于数据库列等每个字节都很重要的场景。

Python 3.8+
import json

payload = {
    "endpoint": "/api/v2/events",
    "filters": {"status": "active", "limit": 100},
    "sort": "desc"
}

# 默认 — 分隔符后有空格(可读)
default_out = json.dumps(payload)
# {"endpoint": "/api/v2/events", "filters": {"status": "active", "limit": 100}, "sort": "desc"}
# len = 88

# 紧凑 — 完全无空格
compact_out = json.dumps(payload, separators=(',', ':'))
# {"endpoint":"/api/v2/events","filters":{"status":"active","limit":100},"sort":"desc"}
# len = 80  (节省 9%;对更大、嵌套更深的 payload 效果更明显)

# 紧凑 + 排序键,用于可复现的缓存键或内容哈希
canonical = json.dumps(payload, separators=(',', ':'), sort_keys=True)
print(canonical)
# {"endpoint":"/api/v2/events","filters":{"limit":100,"status":"active"},"sort":"desc"}
注意:同时传入 indent= separators= 时,separators 参数仅控制 内联分隔符——indent 产生的换行和缩进仍会保留。 若要输出紧凑的单行结果,请省略 indent(或传入 None),并设置 separators=(',', ':')

使用 default 参数序列化自定义 Python 对象

标准 json 模块可序列化 dict、list、字符串、数字、布尔值和 None——但对任何其他类型都会抛出 TypeError。 在生产代码中最常见的两类是 datetime 对象和 UUID

Python 3.8+ — 无自定义处理时的 TypeError
import json
from datetime import datetime, timezone
import uuid

order = {
    "order_id": uuid.uuid4(),            # ❌ TypeError: UUID is not JSON serializable
    "placed_at": datetime.now(timezone.utc),  # ❌ TypeError: datetime is not JSON serializable
    "total_usd": 142.50,
    "items": ["pro-subscription", "addon-storage"]
}

json.dumps(order)  # 抛出 TypeError

方法一 — default= 参数

default= 传入一个可调用对象。 json.dumps() 会对所有无法处理的对象调用它。返回一个可序列化的表示,或对不明确支持的类型抛出 TypeError—— 永远不要静默忽略未知类型。

Python 3.8+
import json
from datetime import datetime, timezone, date
import uuid
from decimal import Decimal

def json_default(obj):
    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    if isinstance(obj, uuid.UUID):
        return str(obj)
    if isinstance(obj, Decimal):
        return float(obj)
    raise TypeError(f"Type {type(obj).__name__!r} is not JSON serializable")

order = {
    "order_id": uuid.uuid4(),
    "placed_at": datetime(2024, 5, 1, 10, 30, 0, tzinfo=timezone.utc),
    "total_usd": Decimal("142.50"),
    "items": ["pro-subscription", "addon-storage"]
}

print(json.dumps(order, indent=4, default=json_default))
# {
#     "order_id": "a3f1c2d4-e5b6-7890-abcd-ef1234567890",
#     "placed_at": "2024-05-01T10:30:00+00:00",
#     "total_usd": 142.5,
#     "items": ["pro-subscription", "addon-storage"]
# }

方法二 — 子类化 json.JSONEncoder

对于需要在多个模块间共享的可复用编码逻辑,子类化 json.JSONEncoder 比到处传递 default 函数更为简洁。覆写 default 方法,并以 super().default(obj) 作为最终兜底——这样可以保留对不支持类型的正确错误行为。

Python 3.8+
import json
from datetime import datetime, timezone
import uuid
from decimal import Decimal

class AppEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.isoformat()
        if isinstance(obj, uuid.UUID):
            return str(obj)
        if isinstance(obj, Decimal):
            return float(obj)
        return super().default(obj)  # 对未知类型抛出 TypeError

order = {
    "order_id": uuid.uuid4(),
    "placed_at": datetime(2024, 5, 1, 10, 30, 0, tzinfo=timezone.utc),
    "total_usd": Decimal("142.50"),
}

# 通过 cls= 传入编码器类
print(json.dumps(order, indent=4, cls=AppEncoder))
# 与 default= 方式的输出完全相同
注意:对于无法识别的类型,始终调用 super().default(obj)(或显式抛出 TypeError)。 对所有类型静默返回 str(obj) 会损坏本应报错的对象—— 这类 bug 在生产环境中极难追踪。

反向解码 — object_hook

编码只是一半。要从 JSON 中重建自定义 Python 对象, 请向 json.loads() json.load() 传入 object_hook 函数。该钩子会对文档中每个解码后的 JSON 对象(dict)调用,并可返回任意 Python 值—— 从而实现完整的编码 ↔ 解码往返。

Python 3.8+
import json
from datetime import datetime
from dataclasses import dataclass

@dataclass
class Event:
    name: str
    occurred_at: datetime
    user_id: str

def encode_event(obj):
    if isinstance(obj, Event):
        return {
            "__type__": "Event",
            "name": obj.name,
            "occurred_at": obj.occurred_at.isoformat(),
            "user_id": obj.user_id,
        }
    raise TypeError(f"Cannot serialize {type(obj)}")

def decode_event(d):
    if d.get("__type__") == "Event":
        return Event(
            name=d["name"],
            occurred_at=datetime.fromisoformat(d["occurred_at"]),
            user_id=d["user_id"],
        )
    return d

# 编码
event = Event("login", datetime(2024, 5, 1, 10, 30), "usr_9f3a2b")
json_str = json.dumps(event, default=encode_event, indent=4)

# 解码回 Event 实例
restored = json.loads(json_str, object_hook=decode_event)
print(type(restored))           # <class 'Event'>
print(restored.occurred_at)     # 2024-05-01 10:30:00
注意:object_hook 会对文档中每个嵌套 dict 调用—— 而非仅顶层。请包含一个鉴别字段(如 "__type__"),以便钩子区分 自定义对象和应保持原样的普通 dict。

pprint — 备选模块(及何时不应使用它)

Python 的 pprint 模块(pretty printer)可将 Python 数据结构格式化以便在终端阅读。 它作用于已解析的 Python 对象,而非 JSON 字符串——其输出使用 Python 语法,而非 JSON 语法。

Python 3.8+
import json, pprint

raw = '{"sensor_id":"s-441","readings":[23.1,23.4,22.9],"unit":"celsius","active":true}'
data = json.loads(raw)

# pprint — 有效的 Python repr,而非有效的 JSON
pprint.pprint(data, sort_dicts=False)
# {'sensor_id': 's-441',
#  'readings': [23.1, 23.4, 22.9],
#  'unit': 'celsius',
#  'active': True}        ← Python True,而非 JSON true

# json.dumps — 有效的 JSON
print(json.dumps(data, indent=4))
# {
#     "sensor_id": "s-441",
#     "readings": [23.1, 23.4, 22.9],
#     "unit": "celsius",
#     "active": true      ← 有效的 JSON
# }
警告:永远不要将 pprint 的输出发送给 API 端点或写入 .json 文件——任何期望标准语法的 JSON 解析器都会报错。 对所有必须是有效 JSON 的输出,请使用 json.dumps(indent=4)

适合使用 pprint 的场景:在 REPL 或调试日志中快速查看 Python 对象,尤其是当对象包含不可 JSON 序列化的类型 (set、自定义类实例、转换前的 dataclass)时。

如何格式化 Requests 的 JSON 响应

最常见的真实场景:磁盘上有一个 JSON 文件,或从 API 获取了一个 HTTP 响应, 需要将其格式化以便调试或记录日志。两种情况使用相同的方式——先解析为 Python dict, 再用 json.dumps() 格式化。

从文件读取

Python 3.8+
import json

try:
    with open("config.json", "r", encoding="utf-8") as f:
        data = json.load(f)

    # 格式化输出到控制台
    print(json.dumps(data, indent=4, ensure_ascii=False))

    # 或将格式化版本写回磁盘
    with open("config.pretty.json", "w", encoding="utf-8") as f:
        json.dump(data, f, indent=4, ensure_ascii=False)

except json.JSONDecodeError as e:
    print(f"无效 JSON: {e}")
except FileNotFoundError:
    print(f"文件未找到: config.json")

格式化 API 响应

Python 3.8+ (需要: pip install requests)
import json, requests
from requests.exceptions import HTTPError, ConnectionError, Timeout

def pretty_print_api(url: str) -> None:
    try:
        resp = requests.get(url, timeout=10)
        resp.raise_for_status()
        print(json.dumps(resp.json(), indent=4, ensure_ascii=False))
    except HTTPError as e:
        print(f"HTTP {e.response.status_code}: {e}")
    except (ConnectionError, Timeout) as e:
        print(f"网络错误: {e}")
    except json.JSONDecodeError:
        print(f"响应体不是 JSON:\n{resp.text[:500]}")

pretty_print_api("https://api.github.com/repos/python/cpython")
注意:response.json() 已完成响应体的解析—— 无需再单独调用 json.loads()。访问 .json() 前请始终添加 raise_for_status(), 以便在 4xx/5xx 错误导致令人困惑的解析错误之前将其捕获。

命令行格式化

Python 内置了 json.tool, 一个可直接在终端格式化 JSON 的 CLI 模块——无需编写 Python 脚本。 任何安装了 Python 的机器上都可用。

bash
# 格式化本地文件
python -m json.tool config.json

# 通过格式化器管道传输 API 响应
curl -s https://api.github.com/users/gvanrossum | python -m json.tool

# 从标准输入格式化
echo '{"service":"api-gateway","version":"2.1.0","healthy":true}' | python -m json.tool

# 按字母顺序排序键
python -m json.tool --sort-keys data.json

# 自定义缩进(Python 3.9+)
python -m json.tool --indent 2 data.json
注意:Python 3.9 新增了 --indent --no-indent 标志。如需更强大的终端 JSON 过滤, 可考虑 jq——但 python -m json.tool 已能在零额外依赖的情况下满足格式化需求。

如果根本不在终端 — 比如粘贴 Postman 响应或日志文件 — ToolDeck JSON 格式化工具 可以让你在一步内完成粘贴、格式化和复制,内置语法高亮和验证。

替代库:orjson 和 rich

orjson — 快 5–10 倍,原生支持更多类型

标准 json 模块对大多数场景已足够快,但如果每秒需要序列化数千个对象——日志管道、高吞吐量 API、 大规模数据导出——orjson 快 5–10 倍。它还原生支持标准库在没有自定义 default 函数时无法序列化的类型: datetime uuid.UUID、 numpy 数组以及 dataclass。

bash — 安装
pip install orjson
Python 3.8+
import orjson
from datetime import datetime, timezone
import uuid

event = {
    "event_id": uuid.uuid4(),                  # 无需 str() — orjson 处理 UUID
    "timestamp": datetime.now(timezone.utc),   # 无需 isoformat()
    "service": "auth-service",
    "level": "INFO",
    "payload": {
        "user_id": "usr_9f3a2b",
        "action": "login",
        "ip": "192.168.1.42",
        "latency_ms": 34
    }
}

# orjson.dumps 返回 bytes;.decode() 转换为 str
print(orjson.dumps(event, option=orjson.OPT_INDENT_2).decode())
# {
#   "event_id": "a3f1c2d4-e5b6-7890-abcd-ef1234567890",
#   "timestamp": "2024-05-01T10:30:00+00:00",
#   "service": "auth-service",
#   ...
# }

需要注意两点: orjson.dumps() 返回 bytes, 而非字符串——如需字符串请调用 .decode()。 它仅通过 OPT_INDENT_2 支持 2 空格缩进;如需 4 空格输出,请使用标准 json.dumps(indent=4)

rich — 终端语法高亮

如果你经常在终端或 REPL 中查看 JSON, rich 可渲染带颜色的语法高亮输出,让深层嵌套结构一目了然。键、字符串、数字和布尔值 各有不同颜色——远比一大片单色文本容易扫读。这是一个仅用于调试的工具,不适用于生产序列化。

bash — 安装
pip install rich
Python 3.8+
from rich import print_json
import json

# print_json() 接受 JSON 字符串
raw = '{"event":"login","user_id":"usr_9f3a2b","timestamp":"2024-05-01T10:30:00Z","success":true,"meta":{"ip":"192.168.1.42","attempts":1}}'
print_json(raw)

# 要格式化 Python dict,先转换为字符串
data = {
    "status": "success",
    "count": 42,
    "tags": ["python", "api", "backend"]
}
print_json(json.dumps(data))
警告:rich.print_json() 输出用于终端着色的 ANSI 转义码—— 永远不要捕获此输出写入 .json 文件或作为 API 响应发送。 任何机器可读的输出请使用 json.dumps(indent=4)

simplejson — 标准库的直接替代品

simplejson 正是后来成为 Python 标准 json 模块的那个库——它至今仍独立维护,在小功能上领先于标准库。 它是真正的直接替代品:替换 import 语句,其余代码无需改动。 适合在不编写自定义编码器的情况下需要 Decimal 支持,或针对旧版 Python 环境的场景。

bash — 安装
pip install simplejson
Python 3.8+
import simplejson as json  # 与标准库 API 完全相同
from decimal import Decimal

order = {
    "item": "API subscription",
    "price": Decimal("49.99"),   # stdlib json 在此处会抛出 TypeError
    "quantity": 3,
}

# simplejson 原生序列化 Decimal — 无需 default=
print(json.dumps(order, indent=4, use_decimal=True))
# {
#     "item": "API subscription",
#     "price": 49.99,
#     "quantity": 3
# }
注意:追求纯粹性能时,orjson 是更好的选择。 在需要原生 Decimal 序列化而不想编写自定义编码器时, 或维护已使用 simplejson 的代码库时,选择 simplejson

处理大型 JSON 文件而不耗尽内存

json.load() 在访问任何字段之前会将整个文件读入内存。对于包含数百万条记录或超过 1 GB 的 payload, 这会导致 MemoryError—— 或至少迫使进程大量使用 swap,速度极慢。

使用 ijson 流式处理

ijson 是一个流式 JSON 解析器,从文件对象中逐个生成项目。 你可以遍历数组元素而无需将完整数据集载入内存—— 峰值内存与单个对象的大小成正比,而非文件大小。

bash — 安装
pip install ijson
Python 3.8+
import ijson
from decimal import Decimal

# events.json 结构: {"events": [...数百万个对象...]}
total_revenue = Decimal("0")
login_count = 0

with open("events.json", "rb") as f:   # ijson 需要二进制模式
    for event in ijson.items(f, "events.item"):
        if event.get("type") == "purchase":
            total_revenue += Decimal(str(event["amount_usd"]))
        elif event.get("type") == "login":
            login_count += 1

print(f"Revenue: ${total_revenue:.2f}  |  Logins: {login_count}")
# 处理 2 GB 文件,峰值内存约 30 MB
注意:当文件超过约 50–100 MB 时,从 json.load() 切换到 ijson。低于此阈值时,json.load() 更简单,且由于内部使用 C 扩展解析器, 速度明显更快。超过 100 MB 后,流式处理节省的内存足以抵消额外开销。

NDJSON — 每行一个 JSON 对象

NDJSON(换行符分隔 JSON,也称 JSON Lines 或 .jsonl) 每行存储一个完整的 JSON 对象。日志导出器、Kafka 消费者和数据管道常常产生这种格式, 因为每行可以独立追加和读取——无需解析整个文件就能添加记录。 标准库即可处理,无需额外依赖。

Python 3.8+
import json
from pathlib import Path

# 写入 NDJSON — 每个事件一行
events = [
    {"ts": "2024-05-01T10:00:00Z", "user": "usr_9f3a2b", "action": "login"},
    {"ts": "2024-05-01T10:01:03Z", "user": "usr_9f3a2b", "action": "purchase", "sku": "pro-plan"},
    {"ts": "2024-05-01T10:15:42Z", "user": "usr_4ab1d9", "action": "login"},
]

with open("events.ndjson", "w", encoding="utf-8") as f:
    for event in events:
        f.write(json.dumps(event, ensure_ascii=False) + "\n")

# 读取 NDJSON — 无论文件多大,内存恒定
purchase_count = 0
with open("events.ndjson", "r", encoding="utf-8") as f:
    for line in f:
        line = line.strip()
        if not line:           # 跳过空行
            continue
        event = json.loads(line)
        if event.get("action") == "purchase":
            purchase_count += 1
            print(f"{event['ts']} — {event['user']} bought {event['sku']}")

常见错误

我在几乎每次涉及 JSON 序列化的代码审查中都见过这四个错误—— 尤其是来自 JavaScript 的开发者,因为 JavaScript 的 JSON.stringify 会自动处理编码。

使用 print(data) 而非 json.dumps()

问题: 对 dict 使用 print() 会输出 Python repr——显示 True/None(Python 语法),而非 true/null(JSON 语法)。这不是有效的 JSON。

解决方案: 始终使用 json.dumps(data, indent=4) 输出有效、可读的 JSON。

Before · Python
After · Python
data = {"active": True, "count": None}
print(data)
# {'active': True, 'count': None}
print(json.dumps(data, indent=4))
# {
#     "active": true,
#     "count": null
# }
处理非 ASCII 文本时忘记 ensure_ascii=False

问题: 特殊字符(汉字、带重音字母、emoji)被转义为 \\uXXXX 序列,使输出无法阅读。

解决方案: 传入 ensure_ascii=False 以保留原始 Unicode 字符。

Before · Python
After · Python
user = {"name": "王芳", "city": "北京"}
json.dumps(user, indent=2)
# {"name": "\u738b\u82b3", "city": "\u5317\u4eac"}
json.dumps(user, indent=2, ensure_ascii=False)
# {"name": "王芳", "city": "北京"}
用 json.dumps() 写入文件

问题: json.dumps() 返回字符串;然后还需要单独调用 f.write(),创建了不必要的中间字符串。

解决方案: 使用 json.dump(data, f, indent=4)——它直接写入文件对象。

Before · Python
After · Python
with open("out.json", "w") as f:
    f.write(json.dumps(data, indent=4))
with open("out.json", "w", encoding="utf-8") as f:
    json.dump(data, f, indent=4, ensure_ascii=False)
用 pprint 格式化并期望得到有效 JSON

问题: pprint.pprint() 使用 Python 语法(True、None、单引号),JSON 解析器会拒绝这种输出。

解决方案: 对任何必须可解析为 JSON 的输出,使用 json.dumps(indent=4)。

Before · Python
After · Python
import pprint
pprint.pprint({"running": True, "last_error": None})
# {'running': True, 'last_error': None}
import json
print(json.dumps({"running": True, "last_error": None}, indent=4))
# {"running": true, "last_error": null}

方法对比 — json.dumps、orjson、simplejson、rich

日常格式化和文件写入使用 json.dumps()—— 零依赖即可覆盖 95% 的场景。在热路径中序列化,或对象包含 datetime UUID 字段时选用 orjson。 需要开箱即用的 Decimal 支持同时保持与标准库兼容时,使用 simplejson。 将 rich.print_json() pprint 严格限制在本地终端查看——两者均不产生机器可读的输出。

方法
输出
有效JSON
速度
Non-ASCII
自定义类型
安装
json.dumps(indent=4)
字符串
标准
ensure_ascii=False
default= / JSONEncoder
内置
json.dump(f, indent=4)
文件
标准
ensure_ascii=False
default= / JSONEncoder
内置
pprint.pprint()
Python repr
标准
原生
✅ (任意 repr)
内置
orjson.dumps(OPT_INDENT_2)
Bytes
5–10× 更快
原生
datetime, UUID, numpy
pip install orjson
python -m json.tool
CLI 标准输出
标准
内置
simplejson.dumps()
字符串
~1.5× 更快
ensure_ascii=False
原生支持 Decimal
pip install simplejson
rich.print_json()
仅终端
✅ (输入)
标准
pip install rich

常见问题

如何在 Python 中格式化输出 JSON?

调用 json.dumps(data, indent=4)。indent 参数设置每个嵌套级别的空格数。先导入 json 模块——它是 Python 标准库的一部分,无需 pip install。如果数据包含非 ASCII 字符(如汉字或表情符号),请传入 ensure_ascii=False。

python
import json

user = {"username": "li_ming", "plan": "enterprise", "permissions": ["read", "write", "deploy"]}
print(json.dumps(user, indent=4, ensure_ascii=False))

json.dumps() 和 json.dump() 有什么区别?

json.dumps()(带 "s")返回内存中的格式化字符串。json.dump()(不带 "s")直接写入文件对象——将打开的文件句柄作为第二个参数传入。要将格式化 JSON 写入磁盘,json.dump(data, f, indent=4) 是惯用做法,可避免创建中间字符串。

python
# dumps → 内存中的字符串
formatted = json.dumps(data, indent=4)

# dump → 直接写入文件
with open('output.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, indent=4)

为什么 json.dumps() 显示 \u4e0a\u6d77 而不是实际字符?

默认情况下 ensure_ascii=True 会将每个非 ASCII 字符转义为 \uXXXX 序列。设置 ensure_ascii=False 可保留原始 Unicode 字符。这对包含中文名称、地址或用户生成内容的场景尤为重要。

python
data = {"city": "上海", "greeting": "你好"}

# 默认 — 已转义
json.dumps(data, indent=4)
# {"city": "\u4e0a\u6d77", "greeting": "\u4f60\u597d"}

# 可读形式
json.dumps(data, indent=4, ensure_ascii=False)
# {"city": "上海", "greeting": "你好"}

如何格式化 JSON 字符串(而非 dict)?

先用 json.loads() 解析字符串,再用 json.dumps() 格式化。两个调用可以在一行内链式完成,方便在终端快速查看。

python
import json

raw = '{"endpoint":"/api/v2/users","timeout":30,"retry":true}'
print(json.dumps(json.loads(raw), indent=4))

可以用 pprint 在 Python 中格式化 JSON 吗?

pprint.pprint() 输出的是 Python 对象表示形式,而非有效的 JSON。它使用 True/False/None(Python 语法)而不是 true/false/null(JSON 语法)。绝对不要将 pprint 的输出传给 API 或 JSON 解析器——凡是需要有效 JSON 的场合,请使用 json.dumps(indent=4)。

python
import pprint, json

data = {"active": True, "score": None}

pprint.pprint(data)     # {'active': True, 'score': None}  ← 不是 JSON
json.dumps(data, indent=4)  # {"active": true, "score": null}  ← 有效 JSON

如何在 Python 中按字母顺序对 JSON 键排序?

在 json.dumps() 中添加 sort_keys=True。在命令行中,使用 python -m json.tool --sort-keys data.json。排序后的键使 JSON diff 更易读,一眼就能看出哪些值发生了变化。

python
import json

server = {"workers": 4, "host": "0.0.0.0", "port": 8080, "debug": False}
print(json.dumps(server, indent=4, sort_keys=True))
# {
#     "debug": false,
#     "host": "0.0.0.0",
#     "port": 8080,
#     "workers": 4
# }

Python 提供完整控制 — 自定义序列化器、流式处理、管道集成。当只需要快速检查或分享格式化片段时, ToolDeck JSON 格式化工具 是更快的方式:粘贴 JSON 即可获得带缩进和高亮的结果,无需任何环境配置。

相关工具

也支持:GoJavaScriptBash
MS
Maria SantosBackend Developer

Maria is a backend developer specialising in Python and API integration. She has broad experience with data pipelines, serialisation formats, and building reliable server-side services. She is an active member of the Python community and enjoys writing practical, example-driven guides that help developers solve real problems without unnecessary theory.

DV
Dmitri Volkov技术审阅者

Dmitri is a DevOps engineer who relies on Python as his primary scripting and automation language. He builds internal tooling, CI/CD pipelines, and infrastructure automation scripts that run in production across distributed teams. He writes about the Python standard library, subprocess management, file processing, encoding utilities, and the practical shell-adjacent Python that DevOps engineers use every day.