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

如何让Pydantic对整数Literal类型执行默认类型强制转换?

如何让Pydantic对Literal类型执行类型强制转换?

我正在用Pydantic的@validate_call装饰器验证函数输入,代码如下:

from typing import Literal
from pydantic import validate_call

@validate_call
def foo(a: Literal[0, 90, 180, 270]) -> None:
    print(a, type(a))

我希望Pydantic能像处理int类型一样执行默认的类型强制转换:

foo(90)    # 按预期工作
foo('90')  # 无法工作,但我希望它能正常运行

如果用a: int作为注解,它会对'180'这类字符串进行强制转换,但之后我得手动验证输入的整数是否符合要求。

注:我接受要求a为字符串类型的解决方案,只要它仍允许整数和字符串输入。


不接受的解决方案

  • 不想添加所有字面量情况。Literal[0, 90, 180, 270, '0', '90', '180', '270']不可行,因为它不允许'-0'或'180.0'这类字符串。
  • 可以用Annotated[int, Field(ge=0, le=0)] | Annotated[int, Field(ge=90, le=90)] | ...,但这太冗长。
  • 不想定义单独的函数或模型。到那种程度,还不如直接接受a: int并在方法内手动验证具体值。

解决方案

可以用Annotated结合BeforeValidator,先将输入强制转换为整数,再用Literal验证是否符合要求。这样既保留了类型强制转换的能力,又不用手动写验证逻辑:

from typing import Literal, Annotated
from pydantic import validate_call, BeforeValidator

@validate_call
def foo(a: Annotated[Literal[0, 90, 180, 270], BeforeValidator(lambda v: int(v))]) -> None:
    print(a, type(a))

测试效果:

foo(90)       # 输出:90 <class 'int'>,正常工作
foo('90')     # 输出:90 <class 'int'>,正常运行
foo('180.0')  # 输出:180 <class 'int'>,可处理带小数的数字字符串
foo('-0')     # 输出:0 <class 'int'>,符合要求

核心逻辑是通过BeforeValidator在Pydantic执行Literal验证前,把任意可转换为int的输入(字符串形式数字、带小数的数字字符串等)转换成整数,之后再检查转换后的数值是否在指定的Literal集合中。如果需要复用转换逻辑,也可以把lambda换成单独定义的函数:

def coerce_to_int(v):
    return int(v)

@validate_call
def foo(a: Annotated[Literal[0, 90, 180, 270], BeforeValidator(coerce_to_int)]) -> None:
    print(a, type(a))

这个方案简洁满足需求,不需要额外定义模型或冗长的注解。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 09:10:19