marshmallow Schema定义字段为何dict()可用而Dict()报错
问题出在同名导入的命名空间覆盖,和marshmallow的Dict字段实现无关。
你的代码里先后执行了两次同名导入:
- 先从
marshmallow.fields导入了字段类Dict - 紧接着从
typing模块导入了用于类型注解的Dict
Python同一作用域下,后导入的同名标识符会直接覆盖之前导入的对象,所以你在Schema类里写output = Dict()时,调用的根本不是marshmallow的字段类,而是typing模块的类型提示对象Dict。
typing模块的Dict是专门给静态类型检查工具用的泛型类,本身不支持实例化,Python 3.8版本专门加了实例化拦截逻辑,只要尝试直接调用就会抛出你看到的类型错误。
至于替换成dict()能正常运行,是因为marshmallow的Schema元类自带原生类型自动映射机制:当类属性赋值为Python原生类型/原生类型实例时,元类会自动将其转换为对应的marshmallow字段实例——你写output = dict()时,元类会自动把它转换成等价的fields.Dict()字段,所以可以正常运行,但这不是因为内置dict替代了marshmallow的Dict字段,而是Schema的自动转换逻辑在生效。
另外你的复现代码里还有两个隐性问题:object_detection = Boolean,、visual_relations = Boolean,两行末尾多了逗号,会把对应属性变成包含字段类的元组,虽然部分版本marshmallow会做容错处理,但长期运行可能出现难以排查的异常,建议去掉多余的尾逗号。
要明确使用marshmallow的Dict字段,只要从根源避免同名覆盖即可,最稳妥的写法是直接通过fields模块调用字段类,不要让单独导入的字段和typing同名类产生冲突:
from marshmallow import Schema, fields from typing import Dict # 这里的Dict只用于类型注解,不会和fields.Dict冲突 class OutSchema(Schema): queryID = fields.String() img_path = fields.String() object_detection = fields.Boolean() visual_relations = fields.Boolean() output = fields.Dict() # 明确指定是marshmallow的Dict字段
如果确实需要单独导入字段,只要给typing的同名类起别名区分即可,不要让两个同名对象在同一作用域共存。
内容的提问来源于stack exchange,提问作者tremendows

