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

8种参数组合的Field函数重载遇MyPy报错,求问题排查

问题背景

我尝试重写Pydantic和SQLModel的Field函数,用3个布尔参数区分8种参数组合,规则如下:

  • 若is_table_field == True,返回SQLModel的FieldInfo,否则返回Pydantic的FieldInfo
  • 若is_state_field == True,必须指定additional_state_description参数;为False则不可指定
  • 若is_tag_field == True,必须指定additional_tag_description参数;为False则不可指定

现有代码

from typing import Literal, overload

from pydantic.fields import FieldInfo as PydanticFieldInfo
from sqlmodel.main import FieldInfo as SQLModelFieldInfo


# TTT
@overload
def Field(
    description: str,
    is_table_field: Literal[True],
    is_state_field: Literal[True],
    is_tag_field: Literal[True],
    additional_state_description: str,
    additional_tag_description: str,
) -> SQLModelFieldInfo:
    ...


# TTF
@overload
def Field(
    description: str, is_table_field: Literal[True], is_state_field: Literal[True], additional_state_description: str
) -> SQLModelFieldInfo:
    ...


# TFT
@overload
def Field(
    description: str, is_table_field: Literal[True], is_tag_field: Literal[True], additional_tag_description: str
) -> SQLModelFieldInfo:
    ...


# TFF
@overload
def Field(description: str, is_table_field: Literal[True]) -> SQLModelFieldInfo:
    ...


# FTT
@overload
def Field(
    description: str,
    is_state_field: Literal[True],
    is_tag_field: Literal[True],
    additional_state_description: str,
    additional_tag_description: str,
) -> PydanticFieldInfo:
    ...


# FTF
@overload
def Field(description: str, is_state_field: Literal[True], additional_state_description: str) -> PydanticFieldInfo:
    ...


# FFT
@overload
def Field(description: str, is_tag_field: Literal[True], additional_tag_description: str) -> PydanticFieldInfo:
    ...


# FFF
@overload
def Field(description: str) -> PydanticFieldInfo:
    ...


def Field(
    description: str,
    is_table_field: bool = False,
    is_state_field: bool = False,
    is_tag_field: bool = False,
    additional_state_description: str | None = None,
    additional_tag_description: str | None = None,
) -> PydanticFieldInfo | SQLModelFieldInfo:
    if is_table_field:
        # TODO: implement
        return SQLModelFieldInfo()

    # TODO: implement
    return PydanticFieldInfo()

MyPy报错信息

  • 重载函数实现不接受签名2的所有可能参数
  • 重载函数实现不接受签名3的所有可能参数
  • 重载函数实现不接受签名5的所有可能参数
  • 重载函数实现不接受签名6的所有可能参数
  • 重载函数实现不接受签名7的所有可能参数

问题原因与解决方法

核心问题

  1. 参数顺序不匹配:重载签名的参数顺序和实现函数的参数顺序不一致,导致调用重载时参数被错误分配。比如TTF重载中的additional_state_description是第四个参数,但实现中第四个参数是is_tag_field,调用时会把additional_state_description的值传给is_tag_field,而additional_state_description会使用默认值None,违反了重载中必须传递该参数的约定。
  2. 重载签名不完整:部分重载未明确指定未使用的布尔参数的默认值,MyPy无法确认这些参数会被设为符合要求的默认值,因此判定签名不兼容。
  3. 缺少运行时校验:实现函数未校验规则2和3的参数约束,无法在运行时保证参数符合约定。

修正后的代码

from typing import Literal, overload

from pydantic.fields import FieldInfo as PydanticFieldInfo
from sqlmodel.main import FieldInfo as SQLModelFieldInfo


# TTT
@overload
def Field(
    description: str,
    is_table_field: Literal[True],
    is_state_field: Literal[True],
    is_tag_field: Literal[True],
    additional_state_description: str,
    additional_tag_description: str,
) -> SQLModelFieldInfo:
    ...


# TTF
@overload
def Field(
    description: str,
    is_table_field: Literal[True],
    is_state_field: Literal[True],
    additional_state_description: str,
    is_tag_field: Literal[False] = False,
) -> SQLModelFieldInfo:
    ...


# TFT
@overload
def Field(
    description: str,
    is_table_field: Literal[True],
    is_tag_field: Literal[True],
    additional_tag_description: str,
    is_state_field: Literal[False] = False,
) -> SQLModelFieldInfo:
    ...


# TFF
@overload
def Field(
    description: str,
    is_table_field: Literal[True],
    is_state_field: Literal[False] = False,
    is_tag_field: Literal[False] = False,
) -> SQLModelFieldInfo:
    ...


# FTT
@overload
def Field(
    description: str,
    is_state_field: Literal[True],
    is_tag_field: Literal[True],
    additional_state_description: str,
    additional_tag_description: str,
    is_table_field: Literal[False] = False,
) -> PydanticFieldInfo:
    ...


# FTF
@overload
def Field(
    description: str,
    is_state_field: Literal[True],
    additional_state_description: str,
    is_tag_field: Literal[False] = False,
    is_table_field: Literal[False] = False,
) -> PydanticFieldInfo:
    ...


# FFT
@overload
def Field(
    description: str,
    is_tag_field: Literal[True],
    additional_tag_description: str,
    is_state_field: Literal[False] = False,
    is_table_field: Literal[False] = False,
) -> PydanticFieldInfo:
    ...


# FFF
@overload
def Field(
    description: str,
    is_table_field: Literal[False] = False,
    is_state_field: Literal[False] = False,
    is_tag_field: Literal[False] = False,
) -> PydanticFieldInfo:
    ...


def Field(
    description: str,
    is_table_field: bool = False,
    is_state_field: bool = False,
    additional_state_description: str | None = None,
    is_tag_field: bool = False,
    additional_tag_description: str | None = None,
) -> PydanticFieldInfo | SQLModelFieldInfo:
    # 校验规则2:is_state_field为True时必须传值,否则不能传
    if is_state_field:
        if additional_state_description is None:
            raise ValueError("当is_state_field为True时,必须指定additional_state_description")
    else:
        if additional_state_description is not None:
            raise ValueError("当is_state_field为False时,不可指定additional_state_description")
    
    # 校验规则3:is_tag_field为True时必须传值,否则不能传
    if is_tag_field:
        if additional_tag_description is None:
            raise ValueError("当is_tag_field为True时,必须指定additional_tag_description")
    else:
        if additional_tag_description is not None:
            raise ValueError("当is_tag_field为False时,不可指定additional_tag_description")
    
    # 拼接完整描述并返回对应FieldInfo
    full_description = description
    if is_state_field:
        full_description += f" | {additional_state_description}"
    if is_tag_field:
        full_description += f" | {additional_tag_description}"
    
    if is_table_field:
        return SQLModelFieldInfo(description=full_description)
    return PydanticFieldInfo(description=full_description)

修正说明

  • 调整参数顺序:将additional_state_description放在is_state_field之后,additional_tag_description放在is_tag_field之后,让重载与实现的参数顺序匹配,避免位置参数分配错误。
  • 完善重载签名:在重载中明确添加未使用布尔参数的默认值(如is_tag_field: Literal[False] = False),让MyPy确认参数符合约束,消除签名不兼容错误。
  • 添加运行时校验:实现规则2和3的校验逻辑,确保运行时参数符合约定。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 18:35:07