如何用字典实例化含自定义嵌套类型的Python对象?
解决嵌套类实例化与类型校验的问题
咱们先拆解你遇到的两个核心问题,再一步步给出解决方案:
第一个错误的根源
你原来的ensure_type函数只会校验已有值的类型,但你的education字段是字典列表([{'school_name':'foo'}, ...]),这些字典还没有被实例化成Education对象,直接让它校验是否是Education类型,肯定会触发类型错误——因为字典本来就不是Education实例呀!
第二个错误的原因
你改成self.education = Education(kwargs.get('education'))后,相当于把整个列表[{'school_name':'foo'}, ...]传给了Education的__init__,但Education的构造函数只接受关键字参数(**kwargs),不接受位置参数,所以才会报“参数数量不匹配”的错误。
解决方案:改造类型校验函数,支持自动实例化嵌套类
我们需要让ensure_type不仅能校验类型,还能在遇到字典(或字典列表)且目标类型是类时,自动把字典转换成对应的类实例。同时还要保留必填字段的校验逻辑。
1. 改造ensure_type函数
def ensure_type(value, types): # 处理列表:逐个元素校验/转换 if isinstance(value, list): return [ensure_type(element, types) for element in value] # 处理字典:如果目标是类,就用字典实例化;否则递归校验字典值 elif isinstance(value, dict): if isinstance(types, type): return types(**value) else: for k, v in value.items(): value[k] = ensure_type(v, types) return value # 普通类型直接校验 elif isinstance(value, types): return value else: raise TypeError(f'Value {value} is {type(value)}, but should be {types}!')
2. 调整类的构造函数,增加必填字段校验
我们在__init__里先检查必填字段是否存在,再用改造后的ensure_type做类型校验和实例化:
class Education: def __init__(self, **kwargs): # 校验必填字段 if 'school_name' not in kwargs: raise ValueError('"school_name" is a required field for Education') self.school_name = ensure_type(kwargs['school_name'], str) class Employee: def __init__(self, **kwargs): # 校验必填字段 if 'fname' not in kwargs: raise ValueError('"fname" is a required field for Employee') if 'education' not in kwargs: raise ValueError('"education" is a required field for Employee') self.fname = ensure_type(kwargs['fname'], str) # 这里传入Education作为类型,函数会自动把字典列表转成Education实例列表 self.education = ensure_type(kwargs['education'], Education)
3. 测试代码
运行你的测试代码:
if __name__ == "__main__": emp_dict = {'fname': 'Bob', 'education': [{'school_name':'foo'}, {'school_name':'bar'}]} employee1 = Employee(**emp_dict) # 验证结果 print(employee1.fname) # 输出: Bob print([edu.school_name for edu in employee1.education]) # 输出: ['foo', 'bar']
这样就能正确实例化嵌套类,同时保证必填字段不缺失,类型也符合要求。
内容的提问来源于stack exchange,提问作者tafteh
相关产品推荐
相关产品推荐

