是否可以将 Literal 类型传递给函数并让该函数输出该 Literal 类型的值?

Hub*_*bro 6 python mypy python-typing

我正在尝试编写一个函数来断言用户输入与定义的文字类型匹配。

基本上,给出:

MyLiteral = Literal["foo", "bar"]
Run Code Online (Sandbox Code Playgroud)

我想编写一个函数来执行此操作:

some_user_provided_value = input()   # For example

good_value = assert_literal(MyLiteral, some_user_provided_value)
Run Code Online (Sandbox Code Playgroud)

现在应该将的类型good_value推断为MyLiteral。如果用户值与任何定义的文字字符串都不匹配,则会引发断言错误。

这应该具有与以下相同的效果:

some_user_provided_value = input()   # For example

good_value: MyLiteral

if some_user_provided_value == "foo":
    good_value = "foo"
elif some_user_provided_value == "bar":
    good_value = "bar"
else:
    raise AssertionError(f"Value {some_user_provided_value!r} is not a MyLiteral")
Run Code Online (Sandbox Code Playgroud)

这是我的项目中经常重复的模式,因此我想将其包装在一个函数中。

该函数看起来像这样:

from typing import Any, TypeVar

T = TypeVar("T")


def assert_literal(literal_type: T, value: Any) -> T:
    if value not in typing.get_args(literal_type):
        raise AssertionError(f"Value {value!r} is not a {literal_type!r}")

    return typing.cast(T, value)
Run Code Online (Sandbox Code Playgroud)

当然,这是行不通的,因为这个函数当前需要一个type 的实例T,并且它将输出一个type 的实例T。

如果我处理常规类,我可以将参数设置为 type Type[T],但是当我使用 Literal 类型时,这会在我脸上爆炸,大概是因为"foo"不是 的实例,MyLiteral这甚至没有任何意义。

目前有什么方法可以实现我想要做的事情吗?还可以和sLiterals混合吗?TypeVar

yot*_*nor -1

名为pydantic的精彩库恰恰提供了这一点。从他们的主页描述来看:

pydantic 在运行时强制执行类型提示,并在数据无效时提供用户友好的错误。

这是文字类型的示例,可在此处找到:

from typing import Literal

from pydantic import BaseModel, ValidationError


class Pie(BaseModel):
    flavor: Literal['apple', 'pumpkin']


Pie(flavor='apple')
Pie(flavor='pumpkin')
try:
    Pie(flavor='cherry')
except ValidationError as e:
    print(str(e))
    """
    1 validation error for Pie
    flavor
      unexpected value; permitted: 'apple', 'pumpkin'
    (type=value_error.const; given=cherry; permitted=('apple', 'pumpkin'))
    """

Run Code Online (Sandbox Code Playgroud)

我会安全地依赖这个库来为你完成繁重的工作(例如,它在流行的 FastAPI 框架中使用) - 但如果你想自己做,那么我会转到他们的源代码,看看他们是如何管理的要做到这一点。

祝你好运!