键入:从有效值列表动态创建文字别名
typing: Dynamically Create Literal Alias from List of Valid Values
我有一个函数可以验证其参数以仅接受给定有效选项列表中的值。在输入方面,我使用 Literal
类型别名来反映这种行为,如下所示:
from typing import Literal
VALID_ARGUMENTS = ['foo', 'bar']
Argument = Literal['foo', 'bar']
def func(argument: 'Argument') -> None:
if argument not in VALID_ARGUMENTS:
raise ValueError(
f'argument must be one of {VALID_ARGUMENTS}'
)
# ...
这违反了 DRY 原则,因为我必须重写我的 Literal 类型定义中的有效参数列表,即使它已经存储在变量 VALID_ARGUMENTS
中。 如何在给定 VALID_ARGUMENTS
变量的情况下动态创建 Argument
文字类型?
以下操作不起作用:
from typing import Literal, Union, NewType
Argument = Literal[*VALID_ARGUMENTS] # SyntaxError: invalid syntax
Argument = Literal[VALID_ARGUMENTS] # Parameters to generic types must be types
Argument = Literal[Union[VALID_ARGUMENTS]] # TypeError: Union[arg, ...]: each arg must be a type. Got ['foo', 'bar'].
Argument = NewType(
'Argument',
Union[
Literal[valid_argument]
for valid_argument in VALID_ARGUMENTS
]
) # Expected type 'Type[_T]', got 'list' instead
那么,如何才能做到呢?还是根本做不到?
反过来,从 Argument
:
构建 VALID_ARGUMENTS
Argument = typing.Literal['foo', 'bar']
VALID_ARGUMENTS: typing.Tuple[Argument, ...] = typing.get_args(Argument)
可以在运行时从 VALID_ARGUMENTS
构建 Argument
,但这样做与静态分析不兼容,静态分析是类型注释的主要用例。从 Argument
构建 VALID_ARGUMENTS
是必经之路。
我在这里为 VALID_ARGUMENTS
使用了一个元组,但如果出于某种原因你真的更喜欢列表,你可以得到一个:
VALID_ARGUMENTS: typing.List[Argument] = list(typing.get_args(Argument))
这是解决此问题的方法。但是不知道是不是一个好的解决方案。
VALID_ARGUMENTS = ['foo', 'bar']
Argument = Literal['1']
Argument.__args__ = tuple(VALID_ARGUMENTS)
print(Argument)
# typing.Literal['foo', 'bar']
如果有人仍在为此寻找解决方法:
typing.Literal[tuple(VALID_ARGUMENTS)]
我有一个函数可以验证其参数以仅接受给定有效选项列表中的值。在输入方面,我使用 Literal
类型别名来反映这种行为,如下所示:
from typing import Literal
VALID_ARGUMENTS = ['foo', 'bar']
Argument = Literal['foo', 'bar']
def func(argument: 'Argument') -> None:
if argument not in VALID_ARGUMENTS:
raise ValueError(
f'argument must be one of {VALID_ARGUMENTS}'
)
# ...
这违反了 DRY 原则,因为我必须重写我的 Literal 类型定义中的有效参数列表,即使它已经存储在变量 VALID_ARGUMENTS
中。 如何在给定 VALID_ARGUMENTS
变量的情况下动态创建 Argument
文字类型?
以下操作不起作用:
from typing import Literal, Union, NewType
Argument = Literal[*VALID_ARGUMENTS] # SyntaxError: invalid syntax
Argument = Literal[VALID_ARGUMENTS] # Parameters to generic types must be types
Argument = Literal[Union[VALID_ARGUMENTS]] # TypeError: Union[arg, ...]: each arg must be a type. Got ['foo', 'bar'].
Argument = NewType(
'Argument',
Union[
Literal[valid_argument]
for valid_argument in VALID_ARGUMENTS
]
) # Expected type 'Type[_T]', got 'list' instead
那么,如何才能做到呢?还是根本做不到?
反过来,从 Argument
:
VALID_ARGUMENTS
Argument = typing.Literal['foo', 'bar']
VALID_ARGUMENTS: typing.Tuple[Argument, ...] = typing.get_args(Argument)
可以在运行时从 VALID_ARGUMENTS
构建 Argument
,但这样做与静态分析不兼容,静态分析是类型注释的主要用例。从 Argument
构建 VALID_ARGUMENTS
是必经之路。
我在这里为 VALID_ARGUMENTS
使用了一个元组,但如果出于某种原因你真的更喜欢列表,你可以得到一个:
VALID_ARGUMENTS: typing.List[Argument] = list(typing.get_args(Argument))
这是解决此问题的方法。但是不知道是不是一个好的解决方案。
VALID_ARGUMENTS = ['foo', 'bar']
Argument = Literal['1']
Argument.__args__ = tuple(VALID_ARGUMENTS)
print(Argument)
# typing.Literal['foo', 'bar']
如果有人仍在为此寻找解决方法:
typing.Literal[tuple(VALID_ARGUMENTS)]