page contents

Python处理JSON,这8个坑我替你踩过了!

说实话,刚学 Python 那会儿我觉得 JSON 简单得不行——不就是个序列化嘛,谁不会?直到有天凌晨两点,我在公司对着一个 TypeError: Object of type datetime is not JSON serializable 怀疑人生。我相信应该不少人见过这个错误。

attachments-2026-03-KvLZ1nvH69c33c0382c9c.png说实话,刚学 Python 那会儿我觉得 JSON 简单得不行——不就是个序列化嘛,谁不会?直到有天凌晨两点,我在公司对着一个 TypeError: Object of type datetime is not JSON serializable 怀疑人生。我相信应该不少人见过这个错误。

今天把这几年踩过的坑、攒下的经验都整理出来,从基础用法讲到进阶技巧,保你看完能少走 80% 的弯路。

一、5 分钟搞定基础(老手可以跳过)

1.1 序列化:Python 对象 → JSON 字符串

import json


data = {

    "name": "张三",

    "age": 28,

    "skills": ["Python", "JavaScript", "Go"]

}

# 转成 JSON 字符串

json_str = json.dumps(data)

print(json_str)

# 输出:'{"name": "\u5f20\u4e09", "age": 28, "skills": ["Python", "JavaScript", "Go"]}'

等等,中文怎么变成 Unicode 了?

别慌,加个参数就行:

json_str = json.dumps(data, ensure_ascii=False)

print(json_str)

# 输出:'{"name": "张三", "age": 28, "skills": ["Python", "JavaScript", "Go"]}'

这个 ensure_ascii=False 我建议你刻在脑子里,99% 的场景都需要它。

1.2 反序列化:JSON 字符串 → Python 对象

json_str = '{"name": "李四", "age": 30, "city": "上海"}'

data = json.loads(json_str)

print(data["name"])  # 输出:李四

print(type(data))    # 输出:<class 'dict'>

1.3 读写文件

# 写入 JSON 文件

with open('data.json', 'w', encoding='utf-8') as f:

    json.dump(data, f, ensure_ascii=False)

# 读取 JSON 文件

with open('data.json', 'r', encoding='utf-8') as f:

    data = json.load(f)

注意:dump/load 是直接操作文件,dumps/loads 是操作字符串(多那个 s 就是 string)。

二、进阶技巧:让代码更优雅

2.1 格式化输出,可读性拉满

默认的 dumps 输出是一行,调试的时候看得眼瞎:

# 丑

json.dumps(data,ensure_ascii=False)

# {"name":"张三","age":28,"skills":["Python","JavaScript"]}

# 美

json.dumps(data, indent=2, ensure_ascii=False)

输出:

{

  "name": "张三",

  "age": 28,

  "skills": [

    "Python",

    "JavaScript"

  ]

}

indent=2 表示缩进 2 个空格,你也可以用 4(看个人喜好)。

2.2 按键排序,方便对比

有时候你需要对比两个 JSON 的差异,但 key 顺序不一样很烦人:

json.dumps(data, sort_keys=True)

# 输出:{"age": 28, "name": "张三", "skills": [...]}

字母顺序排列,diff 的时候清爽多了。

2.3 自定义类型处理(重点!)

这是最容易踩坑的地方。

Python 的 datetime、Decimal、set 这些类型,JSON 根本不认:

from datetime import datetime


data = {

    "name": "王五",

    "created_at": datetime.now()

}

json.dumps(data)  #  TypeError: Object of type datetime is not JSON serializable

解决方案:写个自定义编码器

from datetime import datetime, date

from decimal import Decimal

class CustomEncoder(json.JSONEncoder):

    def default(self, obj):

        if isinstance(obj, (datetime, date)):

            return obj.isoformat()

        if isinstance(obj, Decimal):

            return float(obj)

        if isinstance(obj, set):

            return list(obj)

        return super().default(obj)

# 使用

json.dumps(data, cls=CustomEncoder,ensure_ascii=False)

# 输出:{"name": "王五", "created_at": "2026-03-24T21:54:25.222288"}

更简洁的写法(推荐):

def json_default(obj):

    if isinstance(obj, (datetime, date)):

        return obj.isoformat()

    if isinstance(obj, Decimal):

        return float(obj)

    raise TypeError(f"Object of type {type(obj)} is not JSON serializable")

json.dumps(data, default=json_default)

这个 default 参数我用了无数次,处理各种奇葩类型全靠它。

三、那些年我踩过的坑

坑 1:中文乱码

现象:生成的 JSON 文件里中文全是 \uXXXX

原因:忘了 ensure_ascii=False

解决:

json.dumps(data, ensure_ascii=False)

json.dump(data, f, ensure_ascii=False, encoding='utf-8')

坑 2:文件编码问题

现象:读取 JSON 文件时报错 UnicodeDecodeError

原因:没指定 encoding,Windows 默认用 GBK

解决:

# 永远加上 encoding='utf-8'

with open('data.json', 'r', encoding='utf-8') as f:

    data = json.load(f)

坑 3:嵌套太深导致性能爆炸

现象:处理大 JSON 时程序卡死

原因:JSON 解析是递归的,嵌套太深会栈溢出

解决:

# 限制嵌套深度

json.loads(json_str, strict=False)

# 或者用 ijson 流式处理大文件

import ijson

with open('large.json', 'r') as f:

    for item in ijson.items(f, 'data.item'):

        process(item)

坑 4:浮点数精度丢失

现象:0.1 + 0.2 这种经典问题在 JSON 里也会出现

原因:浮点数本身就是近似值

解决:用 Decimal 处理金额

from decimal import Decimal

price = Decimal('19.99')

# 序列化时转成字符串保留精度

json.dumps({"price": str(price)})

坑 5:循环引用

现象:ValueError: Circular reference detected

原因:对象互相引用,形成死循环

解决:

# 方法 1:忽略循环引用

json.dumps(data, ignore_circular=True)  # Python 3.10+

# 方法 2:自定义处理

def json_default(obj):

    if hasattr(obj, '__dict__'):

        return obj.__dict__

    raise TypeError(f"Object of type {type(obj)} is not JSON serializable")

四、实战:写个配置管理器

最后来个实战,用 JSON 做个简单的配置管理:

import json

from pathlib import Path

from datetime import datetime

class Config:

    def __init__(self, path='config.json'):

        self.path = Path(path)

        self.data = self._load()


    def _load(self):

        if not self.path.exists():

            return {}

        with open(self.path, 'r', encoding='utf-8') as f:

            return json.load(f)


    def save(self):

        with open(self.path, 'w', encoding='utf-8') as f:

            json.dump(self.data, f, indent=2, ensure_ascii=False)


    def get(self, key, default=None):

        return self.data.get(key, default)


    def set(self, key, value):

        self.data[key] = value

        self.save()


# 使用

config = Config()

config.set('last_login', datetime.now().isoformat())

config.set('theme', 'dark')

print(config.get('theme'))  # 输出:dark

这个模式我在好几个项目里用过,简单但够用。

五、总结

核心要点就这些:

1基础用法:dumps/loads 处理字符串,dump/load 处理文件

2中文处理:永远记得 ensure_ascii=False + encoding='utf-8'

3自定义类型:用 default 参数处理 datetime、Decimal 等

4格式化:indent=2 让输出可读,sort_keys=True 方便对比

5性能:大文件用流式处理,别一口气全读进来

最后送一句话:别吝啬那点空格,该格式化就格式化。

更多相关技术内容咨询欢迎前往并持续关注好学星城论坛了解详情。

想高效系统的学习Python编程语言,推荐大家关注一个微信公众号:Python编程学习圈。每天分享行业资讯、技术干货供大家阅读,关注即可免费领取整套Python入门到进阶的学习资料以及教程,感兴趣的小伙伴赶紧行动起来吧。

attachments-2022-05-rLS4AIF8628ee5f3b7e12.jpg

  • 发表于 2026-03-25 09:36
  • 阅读 ( 20 )
  • 分类:Python开发

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
Pack
Pack

1920 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 2228 文章
  3. Pack 1920 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章