Python數(shù)據(jù)類轉(zhuǎn)換為JSON的常用方法總結(jié)
Python 標(biāo)準(zhǔn)庫(kù)的json模塊默認(rèn)無(wú)法直接序列化自定義的dataclass實(shí)例(會(huì)報(bào)Object of type XXX is not JSON serializable),核心原因是json只支持基礎(chǔ)類型(str/int/list/dict 等)。下面我會(huì)從基礎(chǔ)到進(jìn)階給出 4 種優(yōu)雅的轉(zhuǎn)換方法,覆蓋簡(jiǎn)單場(chǎng)景到生產(chǎn)級(jí)復(fù)雜場(chǎng)景,你可根據(jù)需求選擇。
前置準(zhǔn)備:定義測(cè)試數(shù)據(jù)類
先定義一個(gè)典型的嵌套數(shù)據(jù)類,作為后續(xù)轉(zhuǎn)換的示例:
from dataclasses import dataclass, asdict
import json
from datetime import datetime # 包含非基礎(chǔ)類型,模擬真實(shí)場(chǎng)景
# 嵌套子數(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原生類型
address: Address # 嵌套數(shù)據(jù)類
tags: list[str] = None # 可選列表字段
# 創(chuàng)建測(cè)試實(shí)例
test_user = User(
id=1001,
name="張三",
age=28,
register_time=datetime(2026, 1, 19, 10, 30),
address=Address(province="浙江省", city="杭州市", detail="西湖區(qū)XX路"),
tags=["VIP", "新用戶"]
)
方法 1:基礎(chǔ)版 -dataclasses.asdict手動(dòng)轉(zhuǎn)換(簡(jiǎn)單場(chǎng)景)
這是最基礎(chǔ)的優(yōu)雅方式,利用dataclasses內(nèi)置的asdict方法將數(shù)據(jù)類轉(zhuǎn)成字典,再用json.dumps序列化。
代碼實(shí)現(xiàn):
# 步驟1:將dataclass轉(zhuǎn)成普通字典 user_dict = asdict(test_user) # 步驟2:處理非JSON原生類型(如datetime) user_dict["register_time"] = user_dict["register_time"].isoformat() # 步驟3:序列化為JSON字符串 user_json = json.dumps(user_dict, ensure_ascii=False, indent=2) print(user_json)
輸出結(jié)果:
{
"id": 1001,
"name": "張三",
"age": 28,
"register_time": "2026-01-19T10:30:00",
"address": {
"province": "浙江省",
"city": "杭州市",
"detail": "西湖區(qū)XX路"
},
"tags": ["VIP", "新用戶"]
}
關(guān)鍵解釋:
asdict(test_user):核心函數(shù),將數(shù)據(jù)類實(shí)例遞歸轉(zhuǎn)換為普通字典(嵌套的Address也會(huì)被轉(zhuǎn)成字典);ensure_ascii=False:保留中文等非 ASCII 字符,避免轉(zhuǎn)成\uXXXX編碼;indent=2:格式化輸出,提升可讀性;- 需手動(dòng)處理
datetime等非 JSON 原生類型(JSON 僅支持字符串 / 數(shù)字 / 布爾 / 列表 / 字典 /null)。
方法 2:進(jìn)階版 - 自定義JSONEncoder(通用可擴(kuò)展)
如果有多個(gè)數(shù)據(jù)類需要轉(zhuǎn)換,手動(dòng)處理非基礎(chǔ)類型會(huì)很繁瑣,推薦自定義JSONEncoder,實(shí)現(xiàn)統(tǒng)一的序列化規(guī)則。
代碼實(shí)現(xiàn):
class DataclassJSONEncoder(json.JSONEncoder):
"""自定義JSON編碼器,支持dataclass和常見非基礎(chǔ)類型"""
def default(self, obj):
# 第一步:處理dataclass實(shí)例
if hasattr(obj, "__dataclass_fields__"): # 判斷是否是dataclass
return asdict(obj)
# 第二步:處理datetime類型
if isinstance(obj, datetime):
return obj.isoformat()
# 第三步:其他類型交給父類處理(會(huì)拋出標(biāo)準(zhǔn)異常)
return super().default(obj)
# 直接使用自定義編碼器序列化
user_json = json.dumps(
test_user,
cls=DataclassJSONEncoder, # 指定自定義編碼器
ensure_ascii=False,
indent=2
)
print(user_json)
關(guān)鍵解釋:
- 繼承
json.JSONEncoder并重寫default方法:這是json模塊擴(kuò)展序列化規(guī)則的標(biāo)準(zhǔn)方式; __dataclass_fields__:dataclass 實(shí)例的內(nèi)置屬性,用于判斷是否為數(shù)據(jù)類;- 可擴(kuò)展:如需支持
date/UUID等類型,只需在default方法中新增isinstance判斷即可; - 無(wú)需手動(dòng)轉(zhuǎn)字典,直接序列化數(shù)據(jù)類實(shí)例,代碼更簡(jiǎn)潔。
方法 3:優(yōu)化版 - 封裝成工具函數(shù)(復(fù)用性拉滿)
將轉(zhuǎn)換邏輯封裝成工具函數(shù),一鍵調(diào)用,適合項(xiàng)目中多處使用的場(chǎng)景:
def dataclass_to_json(obj, indent=2):
"""
數(shù)據(jù)類轉(zhuǎn)JSON字符串的工具函數(shù)
:param obj: 數(shù)據(jù)類實(shí)例(支持嵌套)
:param indent: 格式化縮進(jìn),None表示緊湊輸出
:return: JSON字符串
"""
return json.dumps(
obj,
cls=DataclassJSONEncoder,
ensure_ascii=False,
indent=indent
)
# 調(diào)用示例(一行搞定)
user_json = dataclass_to_json(test_user)
print(user_json)
方法 4:高級(jí)版 - 使用pydantic(生產(chǎn)環(huán)境推薦)
如果你的場(chǎng)景需要數(shù)據(jù)驗(yàn)證 + 優(yōu)雅序列化,推薦直接使用pydantic(Python 生態(tài)中最主流的數(shù)據(jù)驗(yàn)證庫(kù)),它的BaseModel比原生dataclass更強(qiáng)大,且原生支持 JSON 轉(zhuǎn)換。
前置依賴:
pip install pydantic
代碼實(shí)現(xiàn):
from pydantic import BaseModel
from datetime import datetime
# 替換原生dataclass為pydantic.BaseModel
class Address(BaseModel):
province: str
city: str
detail: str = ""
class User(BaseModel):
id: int
name: str
age: int
register_time: datetime
address: Address
tags: list[str] = None
# 可選:自定義JSON序列化配置(如datetime格式)
class Config:
json_encoders = {
datetime: lambda v: v.strftime("%Y-%m-%d %H:%M:%S") # 自定義時(shí)間格式
}
# 創(chuàng)建實(shí)例(pydantic會(huì)自動(dòng)驗(yàn)證字段類型)
test_user = User(
id=1001,
name="張三",
age=28,
register_time=datetime(2026, 1, 19, 10, 30),
address=Address(province="浙江省", city="杭州市", detail="西湖區(qū)XX路"),
tags=["VIP", "新用戶"]
)
# 原生支持JSON轉(zhuǎn)換(一行搞定)
user_json = test_user.json(ensure_ascii=False, indent=2)
print(user_json)
輸出結(jié)果(時(shí)間格式自定義后):
{
"id": 1001,
"name": "張三",
"age": 28,
"register_time": "2026-01-19 10:30:00",
"address": {
"province": "浙江省",
"city": "杭州市",
"detail": "西湖區(qū)XX路"
},
"tags": ["VIP", "新用戶"]
}
關(guān)鍵優(yōu)勢(shì):
- 原生支持
json()方法:無(wú)需手動(dòng)寫編碼器,開箱即用; - 自動(dòng)數(shù)據(jù)驗(yàn)證:創(chuàng)建實(shí)例時(shí)會(huì)校驗(yàn)字段類型(如
age傳字符串會(huì)直接報(bào)錯(cuò)); - 靈活配置:通過(guò)
Config.json_encoders自定義非基礎(chǔ)類型的序列化規(guī)則; - 支持嵌套、可選字段、默認(rèn)值等,完全兼容原生 dataclass 的用法,且功能更強(qiáng)。
總結(jié)
- 簡(jiǎn)單場(chǎng)景:用
dataclasses.asdict+json.dumps,手動(dòng)處理非基礎(chǔ)類型,快速實(shí)現(xiàn); - 通用場(chǎng)景:自定義
JSONEncoder,統(tǒng)一管理序列化規(guī)則,適合多個(gè)數(shù)據(jù)類的項(xiàng)目; - 生產(chǎn)環(huán)境:優(yōu)先使用
pydantic.BaseModel,兼顧數(shù)據(jù)驗(yàn)證和優(yōu)雅序列化,減少冗余代碼; - 核心原則:避免手動(dòng)拼接字典,利用內(nèi)置工具 / 成熟庫(kù)實(shí)現(xiàn)轉(zhuǎn)換,保證代碼的可維護(hù)性和擴(kuò)展性。
以上就是Python數(shù)據(jù)類轉(zhuǎn)換為JSON的常用方法總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于Python數(shù)據(jù)類轉(zhuǎn)JSON的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
PyTorch如何使用embedding對(duì)特征向量進(jìn)行嵌入
這篇文章主要介紹了PyTorch如何使用embedding對(duì)特征向量進(jìn)行嵌入問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-02-02
Python實(shí)現(xiàn)PDF文字識(shí)別提取并寫入CSV文件
這篇文章主要是和大家分享一個(gè)Python實(shí)現(xiàn)PDF文字識(shí)別與提取并寫入?CSV文件的腳本。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-03-03
Python網(wǎng)絡(luò)請(qǐng)求庫(kù)requests的10個(gè)基本用法
今天我們要聊聊Python中非常實(shí)用的一個(gè)庫(kù)——requests,這個(gè)庫(kù)讓發(fā)送HTTP請(qǐng)求變得超級(jí)簡(jiǎn)單,無(wú)論你是想抓取網(wǎng)頁(yè)數(shù)據(jù)還是測(cè)試API接口,requests都能派上大用場(chǎng),下面我們就一起來(lái)看看如何使用requests完成一些常見的任務(wù),需要的朋友可以參考下2024-10-10
Python使用Turtle實(shí)現(xiàn)精確計(jì)時(shí)工具
這篇文章主要為大家詳細(xì)介紹了Python如何使用Turtle實(shí)現(xiàn)精確計(jì)時(shí)工具,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以參考一下2025-05-05
詳解如何用python實(shí)現(xiàn)一個(gè)簡(jiǎn)單下載器的服務(wù)端和客戶端
這篇文章主要介紹了詳解如何用python實(shí)現(xiàn)一個(gè)簡(jiǎn)單下載器的服務(wù)端和客戶端,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
對(duì)Python中TKinter模塊中的Label組件實(shí)例詳解
今天小編就為大家分享一篇對(duì)Python中TKinter模塊中的Label組件實(shí)例詳解,具有很好的價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-06-06
Python MySQLdb模塊連接操作mysql數(shù)據(jù)庫(kù)實(shí)例
這篇文章主要介紹了Python MySQLdb模塊連接操作mysql數(shù)據(jù)庫(kù)實(shí)例,本文直接給出操作mysql代碼實(shí)例,包含創(chuàng)建表、插入數(shù)據(jù)、插入多條數(shù)據(jù)、查詢數(shù)據(jù)等內(nèi)容,需要的朋友可以參考下2015-04-04
基于Python對(duì)數(shù)據(jù)shape的常見操作詳解
今天小編就為大家分享一篇基于Python對(duì)數(shù)據(jù)shape的常見操作詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-12-12

