Python實(shí)現(xiàn)將JSON數(shù)據(jù)轉(zhuǎn)換為數(shù)據(jù)類的方法匯總
JSON 轉(zhuǎn)數(shù)據(jù)類的核心難點(diǎn)在于:JSON 只有基礎(chǔ)類型(字符串 / 數(shù)字 / 列表 / 字典),而數(shù)據(jù)類包含自定義結(jié)構(gòu)、嵌套類、非 JSON 原生類型(如datetime),需要自動(dòng)映射字段 + 類型轉(zhuǎn)換。下面從「基礎(chǔ)手動(dòng)轉(zhuǎn)換」到「生產(chǎn)級(jí)自動(dòng)轉(zhuǎn)換」給出 3 種優(yōu)雅方案,覆蓋不同場(chǎng)景需求。
前置準(zhǔn)備:定義測(cè)試數(shù)據(jù)類 + 測(cè)試 JSON
先復(fù)用之前的嵌套數(shù)據(jù)類,并準(zhǔn)備對(duì)應(yīng)的 JSON 字符串(模擬真實(shí)場(chǎng)景,包含嵌套、時(shí)間字符串等):
from dataclasses import dataclass, fields
import json
from datetime import datetime
from typing import Optional, Any
# 嵌套子數(shù)據(jù)類
@dataclass
class Address:
province: str
city: str
detail: str = "" # 可選字段
# 主數(shù)據(jù)類
@dataclass
class User:
id: int
name: str
age: int
register_time: datetime # 非JSON原生類型(JSON中是字符串)
address: Address # 嵌套數(shù)據(jù)類
tags: Optional[list[str]] = None # 可選列表字段
# 測(cè)試JSON字符串(模擬接口返回/文件讀取的JSON)
test_json_str = """
{
"id": 1001,
"name": "張三",
"age": 28,
"register_time": "2026-01-19T10:30:00",
"address": {
"province": "浙江省",
"city": "杭州市",
"detail": "西湖區(qū)XX路"
},
"tags": ["VIP", "新用戶"]
}
"""
# 先將JSON字符串轉(zhuǎn)成Python字典(所有方案的前置步驟)
test_json_dict = json.loads(test_json_str)
方法 1:基礎(chǔ)版 - 手動(dòng)映射(簡(jiǎn)單場(chǎng)景,理解底層邏輯)
核心思路:先將 JSON 轉(zhuǎn)字典,再通過「關(guān)鍵字參數(shù)」直接實(shí)例化數(shù)據(jù)類,手動(dòng)處理嵌套類和非基礎(chǔ)類型。
代碼實(shí)現(xiàn):
# 步驟1:處理嵌套數(shù)據(jù)類(Address)
address_dict = test_json_dict.pop("address") # 提取嵌套字典
address = Address(**address_dict) # 字典轉(zhuǎn)嵌套數(shù)據(jù)類
# 步驟2:處理非基礎(chǔ)類型(datetime字符串轉(zhuǎn)datetime對(duì)象)
register_time_str = test_json_dict.pop("register_time")
register_time = datetime.fromisoformat(register_time_str)
# 步驟3:實(shí)例化主數(shù)據(jù)類(剩余字段直接傳參)
user = User(
**test_json_dict, # 展開剩余基礎(chǔ)字段(id/name/age/tags)
address=address,
register_time=register_time
)
# 驗(yàn)證結(jié)果
print(user)
# 輸出:User(id=1001, name='張三', age=28, register_time=datetime.datetime(2026, 1, 19, 10, 30), address=Address(province='浙江省', city='杭州市', detail='西湖區(qū)XX路'), tags=['VIP', '新用戶'])
關(guān)鍵解釋:
**address_dict:利用字典解包,將嵌套字典直接傳給Address的構(gòu)造函數(shù);- 手動(dòng)處理非基礎(chǔ)類型:JSON 中的時(shí)間字符串需要轉(zhuǎn)成
datetime對(duì)象,這是 JSON 轉(zhuǎn)數(shù)據(jù)類的核心痛點(diǎn); - 優(yōu)點(diǎn):邏輯簡(jiǎn)單、易理解;缺點(diǎn):嵌套層級(jí) / 非基礎(chǔ)類型越多,代碼越繁瑣,復(fù)用性差。
方法 2:進(jìn)階版 - 自定義通用轉(zhuǎn)換函數(shù)(可擴(kuò)展,適配多數(shù)據(jù)類)
封裝一個(gè)通用函數(shù),遞歸處理嵌套數(shù)據(jù)類 + 自動(dòng)轉(zhuǎn)換常見非基礎(chǔ)類型,避免重復(fù)寫手動(dòng)映射代碼。
代碼實(shí)現(xiàn):
def json_dict_to_dataclass(data: dict, cls) -> Any:
"""
通用JSON字典轉(zhuǎn)數(shù)據(jù)類函數(shù)(支持嵌套、datetime轉(zhuǎn)換)
:param data: JSON解析后的字典
:param cls: 目標(biāo)數(shù)據(jù)類(如User/Address)
:return: 數(shù)據(jù)類實(shí)例
"""
# 1. 遍歷數(shù)據(jù)類的所有字段
field_map = {f.name: f for f in fields(cls)}
init_kwargs = {}
for field_name, field_type in field_map.items():
# 跳過不存在的字段(可選字段)
if field_name not in data:
continue
value = data[field_name]
target_type = field_type.type
# 2. 處理嵌套數(shù)據(jù)類(判斷是否是dataclass)
if hasattr(target_type, "__dataclass_fields__"):
init_kwargs[field_name] = json_dict_to_dataclass(value, target_type)
# 3. 處理datetime類型(字符串轉(zhuǎn)datetime)
elif target_type is datetime:
init_kwargs[field_name] = datetime.fromisoformat(value)
# 4. 基礎(chǔ)類型直接賦值
else:
init_kwargs[field_name] = value
# 5. 實(shí)例化數(shù)據(jù)類
return cls(**init_kwargs)
# 調(diào)用示例(一行搞定,支持嵌套)
user = json_dict_to_dataclass(test_json_dict, User)
# 驗(yàn)證結(jié)果
print(user)
print(user.address.city) # 訪問嵌套字段:杭州市
print(user.register_time.year) # 訪問datetime字段:2026
關(guān)鍵解釋:
fields(cls):獲取數(shù)據(jù)類的所有字段信息(名稱、類型),實(shí)現(xiàn)動(dòng)態(tài)映射;- 遞歸處理嵌套:如果字段類型是數(shù)據(jù)類(通過
__dataclass_fields__判斷),遞歸調(diào)用函數(shù)轉(zhuǎn)換; - 可擴(kuò)展:如需支持
date/UUID等類型,只需在函數(shù)中新增elif判斷即可; - 優(yōu)點(diǎn):通用、可復(fù)用,適配任意嵌套結(jié)構(gòu)的數(shù) - 據(jù)類;缺點(diǎn):需要自己維護(hù)類型轉(zhuǎn)換邏輯。
方法 3:高級(jí)版 - 使用pydantic(生產(chǎn)環(huán)境推薦,最優(yōu)雅)
pydantic是 Python 生態(tài)中處理數(shù)據(jù)驗(yàn)證 / 轉(zhuǎn)換的主流庫,原生支持 JSON 轉(zhuǎn)模型,自動(dòng)處理類型轉(zhuǎn)換、嵌套、可選字段,無需手動(dòng)寫轉(zhuǎn)換邏輯,是生產(chǎn)環(huán)境的最優(yōu)選擇。
前置依賴:
pip install pydantic
代碼實(shí)現(xiàn):
from pydantic import BaseModel
from datetime import datetime
from typing import Optional, List
# 替換原生dataclass為pydantic.BaseModel(語法幾乎一致,功能更強(qiáng))
class Address(BaseModel):
province: str
city: str
detail: str = ""
class User(BaseModel):
id: int
name: str
age: int
register_time: datetime # 自動(dòng)將ISO格式字符串轉(zhuǎn)datetime
address: Address # 自動(dòng)轉(zhuǎn)換嵌套模型
tags: Optional[List[str]] = None
# 可選:自定義類型轉(zhuǎn)換規(guī)則(如非ISO格式的時(shí)間字符串)
class Config:
json_encoders = {
datetime: lambda v: v.isoformat() # 序列化時(shí)用,反序列化自動(dòng)識(shí)別
}
# 方法1:JSON字符串直接轉(zhuǎn)模型(最優(yōu)雅)
user = User.parse_raw(test_json_str)
# 方法2:JSON字典轉(zhuǎn)模型(兼容已有字典)
# user = User(**test_json_dict)
# 驗(yàn)證結(jié)果
print(user)
# 輸出:id=1001 name='張三' age=28 register_time=datetime.datetime(2026, 1, 19, 10, 30) address=Address(province='浙江省', city='杭州市', detail='西湖區(qū)XX路') tags=['VIP', '新用戶']
# 便捷操作:模型轉(zhuǎn)字典/JSON(反向操作也支持)
print(user.dict()) # 轉(zhuǎn)字典
print(user.json(ensure_ascii=False, indent=2)) # 轉(zhuǎn)格式化JSON字符串
核心優(yōu)勢(shì):
- 零手動(dòng)轉(zhuǎn)換:
parse_raw()直接解析 JSON 字符串為模型,自動(dòng)處理嵌套、datetime等類型; - 自動(dòng)數(shù)據(jù)驗(yàn)證:如果 JSON 數(shù)據(jù)類型錯(cuò)誤(如
age傳字符串),會(huì)直接拋出清晰的異常,避免臟數(shù)據(jù); - 靈活擴(kuò)展:支持自定義類型轉(zhuǎn)換器、可選字段、默認(rèn)值、數(shù)據(jù)校驗(yàn)規(guī)則(如
age >= 0); - 生態(tài)完善:兼容 FastAPI、Django 等框架,是生產(chǎn)環(huán)境處理數(shù)據(jù)的標(biāo)準(zhǔn)方案。
異常示例(數(shù)據(jù)驗(yàn)證):
如果 JSON 中age是字符串"28",pydantic會(huì)拋出明確錯(cuò)誤:
ValidationError: 1 validation error for User age Input should be a valid integer, got a string [type=int_type, input_value='28', input_type=str]
總結(jié)
- 簡(jiǎn)單場(chǎng)景(少量字段 / 無嵌套) :用原生
dataclass+ 手動(dòng)映射,快速實(shí)現(xiàn),無需依賴第三方庫; - 通用場(chǎng)景(多數(shù)據(jù)類 / 嵌套) :封裝自定義轉(zhuǎn)換函數(shù),遞歸處理嵌套和類型轉(zhuǎn)換,提升復(fù)用性;
- 生產(chǎn)環(huán)境(數(shù)據(jù)驗(yàn)證 + 優(yōu)雅轉(zhuǎn)換) :優(yōu)先使用
pydantic.BaseModel,零冗余代碼,自帶驗(yàn)證和自動(dòng)轉(zhuǎn)換,是最優(yōu)雅的方案; - 核心原則:避免手動(dòng)逐個(gè)字段賦值,利用「反射 / 內(nèi)置工具 / 成熟庫」實(shí)現(xiàn)自動(dòng)映射,保證代碼簡(jiǎn)潔且可維護(hù)。
以上就是Python實(shí)現(xiàn)將JSON數(shù)據(jù)轉(zhuǎn)換為數(shù)據(jù)類的方法匯總的詳細(xì)內(nèi)容,更多關(guān)于Python JSON數(shù)據(jù)轉(zhuǎn)數(shù)據(jù)類的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python畫圖常用代碼總結(jié)大全(20個(gè)畫圖代碼現(xiàn)拿現(xiàn)用)
Python是一種高級(jí)編程語言,擁有豐富的圖形庫,可以完成繪制各種類型的圖形任務(wù),下面這篇文章主要給大家介紹了關(guān)于Python畫圖常用代碼的相關(guān)資料,文中介紹的這20個(gè)畫圖代碼可以現(xiàn)拿現(xiàn)用,需要的朋友可以參考下2023-06-06
python中常用檢測(cè)字符串相關(guān)函數(shù)匯總
這篇文章主要介紹了python中常用檢測(cè)字符串相關(guān)函數(shù),實(shí)例匯總了Python針對(duì)字符串?dāng)?shù)字、字母、大小寫等常用檢測(cè)函數(shù),非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04
Python實(shí)現(xiàn)不一樣的猜數(shù)字游戲的示例代碼
大家知道“猜數(shù)字”這個(gè)游戲嗎?顧名思義就是一個(gè)人想一個(gè)數(shù)字,另一個(gè)人猜。本文就來用Python實(shí)現(xiàn)一款不一樣的猜數(shù)字游戲,感興趣的可以了解一下2023-02-02
Python將數(shù)據(jù)生成二維碼的四種方法實(shí)例代碼
二維碼在日常生活中非常常見,廣泛應(yīng)用于支付、登錄驗(yàn)證、信息分享等場(chǎng)景,下面這篇文章主要給大家介紹了關(guān)于Python將數(shù)據(jù)生成二維碼的四種方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-09-09
python關(guān)于倒排列的知識(shí)點(diǎn)總結(jié)
在本篇文章里小編給大家分享的是一篇關(guān)于python關(guān)于倒排列的知識(shí)點(diǎn)總結(jié),有需要的朋友們可以參考下。2020-10-10

