You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python OOP中__dict__赋值JSON引发AttributeError问题求助

解决嵌套类JSON反序列化后的类型问题

嘿,这个问题我之前踩过坑!你猜得没错——问题就出在JSON加载出来的是纯字典/列表这类基本数据类型,直接把它们赋值给__dict__,你的Sentences实例里的属性确实会被填充,但那些嵌套的Words、Characters并不会自动变成类实例,还是保持着JSON加载后的dict形态,所以你用点语法访问charss的时候,自然会报错说dict没有这个属性。

绝对不要修改JSON输入!

先给你明确结论:修改JSON是最糟糕的方案。JSON的核心是作为通用数据格式存在的,要是为了适配你的类结构去改JSON,会让数据和代码强绑定——以后你改类的属性名,JSON也得跟着改;其他程序读取这个JSON也会一脸懵。完全得不偿失。

正确做法:实现自定义反序列化逻辑

你需要做的是把JSON加载后的dict,递归转换成对应的类实例。这里有几种方案,从手动实现到用库简化都有:

方案1:给每个类写from_dict类方法

这是最基础也最可控的方式,每个类自己负责把dict转换成实例,嵌套的类就递归调用:

import json

class Characters:
    def __init__(self, char_content):
        self.charss = char_content  # 这里根据你实际的属性调整,比如单个字符或者字符列表

    @classmethod
    def from_dict(cls, data):
        # 把dict转换成Characters实例
        return cls(char_content=data['charss'])

class Words:
    def __init__(self, chars_list):
        self.charss = chars_list  # 存储Characters实例的列表

    @classmethod
    def from_dict(cls, data):
        # 递归处理每个字符dict,转成Characters实例
        chars_instances = [Characters.from_dict(char_data) for char_data in data['charss']]
        return cls(chars_list=chars_instances)

class Sentences:
    def __init__(self, words_list):
        self.w = words_list  # 存储Words实例的列表

    @classmethod
    def from_dict(cls, data):
        # 递归处理每个单词dict,转成Words实例
        words_instances = [Words.from_dict(word_data) for word_data in data['w']]
        return cls(words_list=words_instances)

# 加载并反序列化的正确姿势
data = json.loads(output.content)
s = Sentences.from_dict(data)

# 现在就能正常访问了!
print(s.w[0].charss[0].charss)

方案2:用dataclasses简化(Python 3.7+)

如果你的类是纯数据类(没有复杂方法),用dataclasses可以减少重复代码,再配合手动的反序列化函数:

from dataclasses import dataclass
from typing import List
import json

@dataclass
class Characters:
    charss: str  # 调整类型为你实际需要的,比如List[str]

@dataclass
class Words:
    charss: List[Characters]

@dataclass
class Sentences:
    w: List[Words]

def deserialize_sentences(data: dict) -> Sentences:
    words = []
    for word_data in data['w']:
        chars = [Characters(**char_data) for char_data in word_data['charss']]
        words.append(Words(charss=chars))
    return Sentences(w=words)

# 使用方式
data = json.loads(output.content)
s = deserialize_sentences(data)

方案3:用pydantic一键搞定(最省心)

如果可以安装第三方库,pydantic是处理嵌套类序列化/反序列化的神器,它会自动帮你处理类型转换,几乎不用写额外代码:

from pydantic import BaseModel
from typing import List
import json

class Characters(BaseModel):
    charss: str

class Words(BaseModel):
    charss: List[Characters]

class Sentences(BaseModel):
    w: List[Words]

# 直接解析JSON字符串,自动转成嵌套实例
s = Sentences.parse_raw(output.content)

# 正常访问属性
print(s.w[0].charss[0].charss)

为什么直接赋值__dict__不行?

__dict__是对象存储属性的字典,但它只是把键值对存进去,不会做任何类型校验或转换。JSON加载出来的w是dict列表,赋值给Sentences的w属性后,它还是dict列表,不是Words实例列表——所以你访问s.w[0]拿到的是dict,用.访问charss自然会报错,因为dict只能用[]访问键。

内容的提问来源于stack exchange,提问作者bcsta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:55:02