jon*_*ach 8 python python-typing
I have a function which validates its argument to accept only values from a given list of valid options. Typing-wise, I reflect this behavior using a Literal type alias, like so:
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}'
)
# ...
Run Code Online (Sandbox Code Playgroud)
这违反了 DRY 原则,因为我必须在我的 Literal 类型的定义中重写有效参数列表,即使它已经存储在变量 中VALID_ARGUMENTS。给定变量,如何Argument动态创建Literal 类型VALID_ARGUMENTS?
下面的事情不工作:
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
Run Code Online (Sandbox Code Playgroud)
那么,如何做到呢?还是根本就做不到?
小智 35
如果有人仍在寻找解决方法:
typing.Literal[tuple(VALID_ARGUMENTS)]
Run Code Online (Sandbox Code Playgroud)
use*_*ica 14
反过来,VALID_ARGUMENTS从Argument以下位置构建:
Argument = typing.Literal['foo', 'bar']
VALID_ARGUMENTS: typing.Tuple[Argument, ...] = typing.get_args(Argument)
Run Code Online (Sandbox Code Playgroud)
有可能在运行时生成Argument的VALID_ARGUMENTS,但这样做是静态分析,它的类型是注释的主要用途的情况下不兼容。VALID_ARGUMENTS从构建Argument是要走的路。
我在VALID_ARGUMENTS这里使用了一个元组,但如果由于某种原因你真的更喜欢一个列表,你可以得到一个:
VALID_ARGUMENTS: typing.List[Argument] = list(typing.get_args(Argument))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1474 次 |
| 最近记录: |