Python序列号源码分析

一、前置准备

Python 的 json 模块一部分是C实现(_json),一部分是纯Python实现(json/encoder.py、json/decoder.py)

👉 读源码优先看纯Python那层,不要一头扎进C代码:

仓库:CPython:https://github.com/python/cpython/tree/main/Lib/json

核心文件:

  • Lib/json/init.py :对外API入口( dump,dumps,load,loads )

  • Lib/json/encoder.py : JSONEncoder 序列化核心(重点读)

  • Lib/json/decoder.py : JSONDecoder 反序列化核心

⚠️ 注意:底层有加速扩展 _json (C写的),默认优先使用;读源码时可以手动禁用C加速,走纯Python路径方便调试:

python

import json

json._json = None # 强制使用纯Python编码器,方便断点跟踪(仅学习用!不要业务代码这么写)

安装源码阅读环境:

  1. clone cpython 仓库,用 VSCode / PyCharm 打开 Lib/json

  2. 断点跟踪: json.dumps(obj) 的调用链路

二、整体架构(宏观笔记模板)

plaintext

项目/模块:Python标准库 json(序列化)

核心作用:实现 Python对象 ↔ JSON字符串 的转换,遵守JSON规范

JSON支持类型:object(dict), array(list), str, int/float, True/False, None

⚠️ JSON不能直接表示:tuple、datetime、自定义类、bytes → 需要扩展

目录&职责:

  • init.py:对外暴露4个主函数,代理给 encoder/decoder

  • encoder.py:JSONEncoder,遍历对象,递归转成可JSON化的类型

  • decoder.py:JSONDecoder,词法扫描→语法解析→构建Python对象

  • scanner.py:词法分析辅助(识别数字、字符串、符号)

入口:json.dumps() #序列化;json.loads() #反序列化

主要API:

json.dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True,

allow_nan=True, cls=None, indent=None, separators=None,

default=None, sort_keys=False, **kw)

json.loads(s, *, cls=None, object_hook=None, parse_float=None,...)

前置知识点:递归、迭代器、异常处理、Python鸭子类型

执行主干链路(dumps)

dumps() → JSONEncoder().encode(obj) → self.iterencode(obj) → _iterencode(obj, _current_indent_level) → 递归分发不同类型的处理逻辑

重点:json 不是反射遍历所有属性的黑魔法,是一套类型分发+递归遍历的算法。

三、精读:encoder.py 核心源码分析(带笔记示范)

下面摘取关键逻辑,并附上「源码阅读笔记」(就是我们上一轮说的笔记风格),省去无关兼容代码。

入口方法 encode :

python

def encode(self, o):

"""Return a JSON string representation of a Python data structure."""

if isinstance(o, str):

if self.ensure_ascii:

return self.encode_basestring_ascii(o)

else:

return self.encode_basestring(o)

chunks = self.iterencode(o, _one_shot=True)

if not isinstance(chunks, (list, tuple)):

chunks = list(chunks)

return ''.join(chunks)

📝笔记:

plaintext

模块:JSONEncoder.encode --- 序列化总入口

功能目标:接收Python对象,输出完整JSON字符串

关键函数:

  • encode:外层入口;真正干活是 iterencode(生成器返回一块块字符串,最后join)

为什么用生成器 iterencode?

👉 大对象时不用一次性构造超长字符串,减少内存占用,流式输出(设计亮点❗)

主干:encode → iterencode → _iterencode(私有递归函数,真正的调度中心)

最核心私有函数 _iterencode (简化版,源码很长,我提炼骨架):

python

def _iterencode(o, _indent):

if o is None:

yield 'null'

elif o is True:

yield 'true'

elif o is False:

yield 'false'

elif isinstance(o, int):

yield str(o)

elif isinstance(o, float):

yield floatstr(o, self.allow_nan)

elif isinstance(o, str):

yield self.encode_basestring(o)

elif isinstance(o, (list, tuple)):

yield '['

first = True

for elem in o:

if not first:

yield ', '

first = False

yield from _iterencode(elem, _indent)

yield ']'

elif isinstance(o, dict):

yield '{'

first = True

items = o.items()

if self.sort_keys:

items = sorted(items)

for k,v in items:

if not first:

yield ', '

first=False

if not isinstance(k, str):

if self.skipkeys:

continue

else:

raise TypeError("key must be str")

yield from _iterencode(k, _indent)

yield ':'

yield from _iterencode(v, _indent)

yield '}'

else:

不能识别的类型,交给 default(),用户可重写!扩展点❗

if self.default is not None:

o = self.default(o)

yield from _iterencode(o, _indent)

else:

raise TypeError(f"Object of type {type(o).name} is not JSON serializable")

📝精读笔记:

plaintext

模块:_iterencode 递归分发逻辑

功能目标:**JSON序列化的核心调度器**,根据对象类型,产出对应的JSON片段

核心数据结构:没有特殊数据结构!就是利用函数递归 + 生成器yield流式输出。

👉 设计亮点(非常值得学习)

  1. **访问者模式思想**:不使用复杂的类继承体系,用大if‑elif做类型分发;

对标准类型内置处理;**非标准类型委托给 default() 钩子做扩展** → 这就是为什么我们可以自定义序列化!

示例:

class MyEncoder(json.JSONEncoder):

def default(self, obj):

if isinstance(obj, datetime.datetime):

return obj.isoformat()

return super().default(obj)

  1. 使用生成器(yield)分块输出:

好处:序列化超大list/dict时,不用在内存里保存完整字符串,内存友好;dump到文件时可以一块一块write。

很多新手自己写序列化会直接拼接字符串 `s += ...`,大量字符串拷贝,效率差。

  1. dict的key强制只能是字符串:JSON标准约束,源码做了严格校验,可选择skipkeys跳过非法key。

边界&异常:

  • 遇到不可序列化类型:若没有default钩子 → 抛TypeError(日常开发最常见报错来源!)

  • float支持nan/inf,但JSON标准不允许,由allow_nan开关控制

我的思考:

如果我自己一开始写,很可能:

  • 直接递归返回str,不用生成器,大对象内存爆炸;

  • 没有预留default扩展点,硬编码所有类型,以后很难扩展;

  • 忘记处理tuple(json当作array),key非字符串等边界。

四、关键配套:循环引用检测(check_circular)

源码里还有一个重要逻辑:循环引用检测,比如 a=\[\], b=a; a.append(b) ,普通递归会无限递归栈溢出。

实现思路:

JSONEncoder 在 iterencode 维护一个 _markers 的id集合,每进入一个容器对象(list/dict),就把 id(obj) 放入集合;退出时移除。如果遇到已存在id → 抛 ValueError: Circular reference detected 。

📝笔记要点:

不是加锁,不是深拷贝;只是记录对象id的访问栈,非常轻量的防递归爆炸方案。很多新手写递归序列化都会漏掉循环引用保护。

五、反序列化简单看(decoder.py

json的解码分为两层:

  1. scanner:把字符串切成 token( { } : "abc" 123 true )------词法分析

  2. JSONDecoder:根据token流,构建dict/list等对象------简单递归下降解析

对新手来说,编码器比解码器容易读得多,建议先吃透 encode,再看 decode,不要同时啃两边。

六、实战练习(源码阅读后的复刻作业,非常重要❗)

按照之前的方法论:读懂后,手写一个极简版序列化器 my_json.py,只支持:None、bool、int、str、list、dict;不处理转义、缩进、循环引用(先简化),然后对比标准库差距。

参考骨架:

python

def my_dumps(obj):

if obj is None:

return "null"

elif isinstance(obj, bool):

return "true" if obj else "false"

elif isinstance(obj, int):

return str(obj)

elif isinstance(obj, str):

return '"' + obj + '"' # 真实要处理 "、\ 等转义,这里省略

elif isinstance(obj, list):

items = ",".join(my_dumps(x) for x in obj)

return f"{items}"

elif isinstance(obj, dict):

parts = \[\]

for k, v in obj.items():

parts.append(f"{my_dumps(str(k))}:{my_dumps(v)}")

return "{" + ",".join(parts) + "}"

else:

raise TypeError(f"cannot serialize {type(obj)}")

if name == "main":

print(my_dumps({"name":"python","nums":1,2,3}))

做完后对比标准库:

  • 缺少字符串转义( " 、 \n )

  • 没有流式生成器,大对象性能差

  • 没有循环引用检测

  • 没有default扩展点

  • 没有skipkeys、sort_keys等能力

👉 这些差异就是你从源码学到的工程细节。

七、阅读路线 & 避坑

  1. 不要一开始去读C版本 _json.c ,先吃透 Lib/json 纯Python逻辑;理解业务逻辑之后,有余力再看C实现做加速对比。

  2. 调试方式:

python

import json

json._json = None

d = {"a":1, "b":2,3}

print(json.dumps(d))

encoder.py 的 _iterencode 打断点,观察每一步 yield 的内容。

  1. 重点学习的3个工程思想:
  • 生成器做流式输出,控制内存

  • default钩子实现可扩展,开闭原则

  • 对象id栈检测循环引用,防栈溢出

相关推荐
计算机源码社1 小时前
【大数据项目实战】基于大数据的影视内容生态综合质量分析与可视化-基于数据挖掘的影视内容类型共现与口碑聚类分析系统
大数据·人工智能·python·数据挖掘·数据分析·毕业设计·课程设计
C^h2 小时前
pytorch 适合初学者 0基础学习
人工智能·pytorch·python
小柯南敲键盘2 小时前
跨马翻译:AI批量图片翻译工具,跨境电商视频字幕翻译与智能抠图一体搞定
人工智能·python·音视频
2601_962297252 小时前
Python里behave和pytest-bdd哪个更适合中大型项目?为什么?
python·bdd·行为驱动开发·behave·pytest-bdd
YCOSA20254 小时前
系统工具使用检测.exe (仅供娱乐)
python·microsoft
2601_962295334 小时前
如何python实现网页的自动化
python·selenium·beautifulsoup·requests·网页自动化
ofoxcoding4 小时前
GPT Image 2.5 API 实战:Python 调用实现图片生成与编辑
人工智能·python·gpt·ai
张小姐的猫5 小时前
【AI大模型接入SDK】 —— Gemini接入封装
android·数据结构·数据库·c++·人工智能·python
Elastic 中国社区官方博客5 小时前
Elasticsearch Python DSL 客户端开发
大数据·数据库·python·elasticsearch·搜索引擎·全文检索