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

Subscripted generics报错排查:向Restaurant添加Menu时遇类型检查问题

解决“Subscripted generics cannot be used with class and instance checks”错误

错误根源

你遇到的错误来自EnforcedTypeClass中的类型校验逻辑:Python的isinstance()函数不支持直接检查下标化的泛型类型(比如List[Section]、Union[Menu, None])。这类泛型在运行时无法直接作为类型参数传入isinstance,导致报错。

修复步骤及代码调整

1. 重构类型校验逻辑

修改EnforcedTypeClass,用typing模块的get_origin和get_args工具解析泛型类型,分别处理Union、List等泛型场景:

from typing import get_origin, get_args, Union, List
from dataclasses import dataclass

@dataclass()
class EnforcedTypeClass:
    def __post_init__(self):
        for name, field_type in self.__annotations__.items():
            value = self.__dict__[name]
            
            # 处理允许为None的字段
            if value is None:
                origin = get_origin(field_type)
                if origin is Union and type(None) in get_args(field_type):
                    continue
                raise TypeError(f"字段`{name}`不能为None,预期类型: {field_type}")
            
            # 解析泛型的原始类型(比如List的原始类型是list)
            origin_type = get_origin(field_type) or field_type
            
            # 处理Union类型:只要匹配任意一个分支即可
            if origin_type is Union:
                valid_types = get_args(field_type)
                if not any(isinstance(value, t) for t in valid_types):
                    current_type = type(value)
                    raise TypeError(f"字段`{name}`赋值类型为{current_type},预期类型: {field_type}")
                continue
            
            # 处理List类型:先检查整体是列表,再检查每个元素的类型
            if origin_type is List:
                item_type = get_args(field_type)[0]
                if not isinstance(value, list):
                    current_type = type(value)
                    raise TypeError(f"字段`{name}`赋值类型为{current_type},预期类型: {field_type}")
                for idx, item in enumerate(value):
                    if not isinstance(item, item_type):
                        item_current_type = type(item)
                        raise TypeError(f"字段`{name}`中第{idx}个元素类型为{item_current_type},预期类型: {item_type}")
                continue
            
            # 普通类型的直接检查
            if not isinstance(value, origin_type):
                current_type = type(value)
                raise TypeError(f"字段`{name}`赋值类型为{current_type},预期类型: {field_type}")

2. 修正update_one语法错误

你的路由代码中update_one的参数格式错误,外层多了一对大括号,正确写法是:

# 修正后
result = restaurants_collection.update_one(
     {"_id": restaurant_id},
     {"$push": {"menu": menu}}
    )

3. 修正menu_id获取逻辑

update_one的返回结果没有inserted_id属性(这是insert_one的属性),如果需要给新增菜单生成ID,可手动用ObjectId创建:

from bson.objectid import ObjectId

# 在创建menu字典后添加
menu = Menu(**data).as_dict()
menu["_id"] = ObjectId()  # 手动生成唯一ID

# 后续返回时直接使用这个ID
return make_response({
    'message': '新菜单已成功存入数据库',
    'data': {"id": menu["_id"], **menu}}), 200

4. 修正Restaurant类的menu类型定义

你用$push往menu字段添加元素,说明数据库中menu是数组类型,但原Restaurant类中menu定义为Union[Menu, None],类型不匹配,需修改为列表类型:

from dataclasses import dataclass, field

@dataclass()
class Restaurant(EnforcedTypeClass):
    name : str
    address : str
    phone_number : str
    email : str
    hours_of_operation : str
    menu : List[Menu] = field(default_factory=list)  # 改为列表,默认空列表
    
    def as_dict(self):
        return {
                'name' : self.name,
                'address' : self.address,
                'phone_number' : self.phone_number,
                'email' : self.email,
                'hours_of_operation' : self.hours_of_operation,
                'menu' : [item.as_dict() for item in self.menu]  # 对象列表转字典列表
        }

额外注意事项

  • 确保Section类已正确定义,若需要类型校验,也应继承EnforcedTypeClass
  • 传入的data中sections字段必须是符合Section类型要求的字典列表,否则会触发类型校验错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 23:45:42