C#转Python第4.4篇:JSON 处理:json 模块 vs System.Text.Json

在 C# 里处理 JSON,要么用 Newtonsoft.Json(Json.NET),要么用 .NET Core 自带的 System.Text.Json。JsonConvert.SerializeObject() 和 JsonSerializer.Deserialize<T>() 是标配,泛型反序列化、JsonProperty 特性、JsonConverter 自定义转换器,功能强大但复杂。

在 Python 里处理 JSON,内置 json 模块,json.dumps() 和 json.loads() 两个函数搞定一切。没有泛型,没有特性,没有转换器,就是字典和列表的序列化/反序列化。

当我第一次在 Python 里处理 JSON 的时候,我的内心是:"这...也太简单了吧?我的泛型呢?我的 JsonProperty 呢?我的 JsonSerializerOptions 呢?"

后来我才明白,Python 的 JSON 处理哲学是:JSON 就是字典的文本表示 ,不需要额外的映射。而 C# 的 JSON 处理哲学是:JSON 是一种数据格式,需要精确地映射到类型系统。

Python 处理 JSON 的思路就是:JSON 就是字典的文本表示,不需要额外的映射层。

基础语法对比

C# 版本:

复制代码
using System.Text.Json;

// 序列化
var user = new { Name = "Alice", Age = 25 };
string json = JsonSerializer.Serialize(user);
// {"Name":"Alice","Age":25}

// 反序列化
string jsonStr = "{\"Name\":\"Alice\",\"Age\":25}";
var user = JsonSerializer.Deserialize<User>(jsonStr);

Python 版本:

复制代码
import json

# 序列化
user = {"name": "Alice", "age": 25}
json_str = json.dumps(user)
# '{"name": "Alice", "age": 25}'

# 反序列化
json_str = '{"name": "Alice", "age": 25}'
user = json.loads(json_str)
# {"name": "Alice", "age": 25}

对比一下:

操作 C# Python
序列化 JsonSerializer.Serialize() json.dumps()
反序列化 JsonSerializer.Deserialize<T>() json.loads()
类型 需要定义类 直接用字典
缩进 WriteIndented = true indent=2
编码 默认 UTF-8 默认 UTF-8

Python 的 JSON 处理像在翻译字典------json.loads() 把 JSON 字符串变成字典,json.dumps() 把字典变成 JSON 字符串。C# 的 JSON 处理像在做数据映射------把 JSON 精确地映射到类的属性上。

缩进格式化

C# 版本:

复制代码
var options = new JsonSerializerOptions { WriteIndented = true };
string json = JsonSerializer.Serialize(user, options);
// {
//     "Name": "Alice",
//     "Age": 25
// }

Python 版本:

复制代码
json_str = json.dumps(user, indent=2)
# {
#   "name": "Alice",
#   "age": 25
# }

Python 只需要 indent=2,C# 需要设置 JsonSerializerOptions。Python 更简洁。

命名策略

C# 的 JSON 命名策略:

复制代码
// 默认 PascalCase
var options = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
string json = JsonSerializer.Serialize(user, options);
// {"name":"Alice","age":25}

// 自定义策略
var options = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
};

Python 默认就是 snake_case,因为 Python 的变量命名习惯就是 snake_case:

复制代码
# Python 的字典键就是变量名风格
user = {"name": "Alice", "age": 25}
json_str = json.dumps(user)
# '{"name": "Alice", "age": 25}'

C# 需要额外配置命名策略,Python 不需要。

特殊值处理

C# 的 JsonSerializerOptions:

复制代码
var options = new JsonSerializerOptions
{
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    WriteIndented = true
};

Python 的 json.dumps 参数:

复制代码
json_str = json.dumps(
    user,
    indent=2,
    ensure_ascii=False,  # 支持中文
    skipkeys=True,       # 跳过不可序列化的键
    sort_keys=True       # 按键排序
)
功能 C# Python
忽略 null DefaultIgnoreCondition separators 或手动过滤
中文支持 默认支持 ensure_ascii=False
键排序 手动实现 sort_keys=True
跳过不可序列化键 异常 skipkeys=True

自定义序列化

C# 的自定义转换器:

复制代码
public class DateTimeConverter : JsonConverter<DateTime>
{
    public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return DateTime.Parse(reader.GetString());
    }

    public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToString("yyyy-MM-dd HH:mm:ss"));
    }
}

// 使用
var options = new JsonSerializerOptions();
options.Converters.Add(new DateTimeConverter());
string json = JsonSerializer.Serialize(dateTime, options);

Python 的自定义序列化:

复制代码
class DateTimeEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.strftime("%Y-%m-%d %H:%M:%S")
        return super().default(obj)

# 使用
json_str = json.dumps({"time": datetime.now()}, cls=DateTimeEncoder)

C# 用泛型转换器,Python 用 JSONEncoder 子类。Python 的方式更简单,但 C# 的方式更类型安全。

JSON 路径查询

C# 需要第三方库(如 JsonPath)来查询 JSON 路径。

Python 有 jsonpath-ng 库:

复制代码
from jsonpath_ng import parse

data = {"users": [{"name": "Alice", "age": 25}, {"name": "Bob", "age": 30}]}
expr = parse("users[*].name")
matches = [match.value for match in expr.find(data)]
# ["Alice", "Bob"]

流式处理

C# 的流式处理:

复制代码
using var stream = File.OpenRead("large.json");
var data = await JsonSerializer.DeserializeAsync<List<User>>(stream);

Python 的流式处理:

复制代码
import ijson  # 需要安装

with open("large.json", "rb") as f:
    for record in ijson.items(f, "users.item"):
        process(record)

Python 的 ijson 可以流式解析大型 JSON 文件,不会一次性加载到内存。

JSON Schema 验证

C# 可以用 JsonSchema.Net 来验证 JSON:

复制代码
var schema = JsonSchema.FromType<User>();
var isValid = schema.Validate(jsonStr);

Python 可以用 jsonschema:

复制代码
from jsonschema import validate

schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "age": {"type": "number"}
    }
}
validate(instance={"name": "Alice", "age": 25}, schema=schema)

迁移指南:C# 开发者最容易犯的错

  1. 忘记 json.loads() 返回字典:Python 的 JSON 反序列化直接返回字典,不是对象

  2. 日期格式不一致 :Python 的 datetime 序列化格式和 C# 不同

  3. 编码问题 :ensure_ascii=False 才能正确处理中文

  4. 键名大小写:Python 默认 snake_case,C# 默认 PascalCase

  5. 空值处理 :Python 的 None 序列化为 null,但反序列化时 null 变成 None

坑点提醒

日期序列化 ------Python 默认不序列化 datetime 对象:

复制代码
from datetime import datetime
json.dumps({"time": datetime.now()})  # TypeError: Object of type datetime is not JSON serializable

解决方案:

复制代码
json.dumps({"time": datetime.now().isoformat()})
# 或者用自定义编码器

浮点数精度------JSON 的浮点数精度问题:

复制代码
import json
json.dumps(0.1 + 0.2)  # '0.30000000000000004'

这不是 Python 的问题,是 IEEE 754 浮点数的标准行为。C# 也有同样的问题。

大数字精度------JSON 的大整数精度:

复制代码
import json
json.dumps(9007199254740993)  # '9007199254740993',但 JavaScript 可能丢失精度

Python 的 int 没有上限,但 JavaScript 的 Number 有精度限制。处理大整数时要注意。

真实案例 :我有个同事从 C# 转 Python,写了一个 API 对接脚本。脚本从 C# 后端获取 JSON 数据,但 Python 反序列化后字典的键是 camelCase(如 userName),而 Python 代码用的是 snake_case(如 user_name)。后来用了一个 humps 库来自动转换键名才解决。

一句话总结

C# 的 JSON 处理像在做数据映射------把 JSON 精确地映射到类型系统;Python 的 JSON 处理像在翻译字典------JSON 就是字典的文本表示,简单直接。

下一篇咱们来聊聊单元测试------C# 的 xUnit/NUnit vs Python 的 pytest,两种语言的"测试哲学"又有啥不同。


📦 示例代码:C# 转 Python 全系列配套练习代码(含 48 章示例)

💬 欢迎点赞、收藏、转发,你的支持是我持续创作的动力!

相关推荐
宿州派大星3 小时前
Python实战:PyQt5 + OpenCV + Dlib 打造AI桌面应用
人工智能·python·qt
承渊政道4 小时前
【从零开始大模型开发与微调:基于PyTorch与ChatGLM】(开源大模型ChatGLM高级定制化应用实战)
人工智能·pytorch·python·llm·模型微调·glm
Smoothcloud润云10 小时前
PyTorch大模型权重加载与启动耗时优化实战:定位磁盘、内存与显存瓶颈
人工智能·pytorch·python·深度学习·gpu算力
databook10 小时前
从循环到向量化:NumPy提速的7个关键思维
python·数据分析·numpy
棉猴11 小时前
玩游戏学Python1-Python和pgzero库的安装
python·pygame·玩游戏·pgzero·pgzrun
诺伦11 小时前
GEO优化数据实证:78%引用流向官网的机制拆解与小品牌三步管线实战教程 | RiseClaw玄策
python·seo·geo·内容营销·ai搜索
oooost11 小时前
pytorch学习笔记1
python·学习方法
数字融合12 小时前
透明化视频孪生虚实映射一体化融合技术
人工智能·python·数码相机
jack1868912 小时前
Lovable.Dev 全栈应用快速落地实战指南
python
华研前沿标杆游学12 小时前
【标杆研学】走进茅台集团|对标学习长期主义与匠心精神
python