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

在 C# 里处理 JSON,要么用 Newtonsoft.JsonJson.NET),要么用 .NET Core 自带的 System.Text.JsonJsonConvert.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 章示例)

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

相关推荐
SelectDB技术团队25 分钟前
统一全文检索与 SQL 分析:Apache Doris 日志分析实践
大数据·数据结构·后端·python·全文检索·doris·日志分析
心中有你021434 分钟前
Python爬虫实战:京东商品数据爬取+可视化分析
开发语言·爬虫·python
jay神2 小时前
2026年YOLO还有哪些创新点可以做?
python·yolo·毕业设计·科研·课程设计·创新
geovindu10 小时前
CSharp: 万年历
开发语言·后端·c#·.net
傲笑风10 小时前
【openvino】tinybert基于openvino服务化部署(四)
人工智能·python·自然语言处理·nlp·bert·openvino
维基框架11 小时前
WIKI 知识库 v1.1.1 正式发布
人工智能·python
谢白羽14 小时前
SGLang的AWQ量化笔记
笔记·python·sglang
迷迭香yy15 小时前
基金档案数据工程实战从收入分析到持仓穿透的Python解析 IG50免费开源股票数据API接口
开发语言·python
清水白石00815 小时前
Python 类型设计深度解析:TypedDict 能否替代 dataclass?从 JSON 数据边界到 API 设计的最佳实践
java·python·json