[英]Can the * (unpacking) operator be typed in Python? Or any other variadic args function such that all variadic types are in the result type?
使用类型存根,我想知道是否可以在 Python 中表达一个类型,允许您为任意数量的 arguments 正确键入:
def test(*args):
return args
乍一看,我带着:
T = TypeVar('T')
def test(*args: T) -> Tuple[T, ...]:
return args
但这当然只会正确输入第一个 T。
是为所有 arities 编写覆盖的唯一可能方法吗?
T1 = TypeVar('T1')
T2 = TypeVar('T2')
T3 = TypeVar('T3')
T4 = TypeVar('T4')
@overload
def test(arg1: T1) -> Tuple[T1]: ...
@overload
def test(arg1: T1, arg2: T2) -> Tuple[T1, T2]: ...
@overload
def test(arg1: T1, arg2: T2, arg3: T3) -> Tuple[T1, T2, T3]: ...
@overload
def test(arg1: T1, arg2: T2, arg3: T3, arg4: T4) -> Tuple[T1, T2, T3, T4]: ...
# etc
def test(*args: Any) -> Tuple[Any, ...]:
return args
这也不完整,因为它没有携带足够的类型信息来键入以下内容:
x: Tuple[int, int, str] = test(*[1, 2, "4"])
TLDR: @overload
目前是唯一可行的方法来注释某种程度的差异。 PEP 646 -- 可变参数 Generics是一个提案草案,以启用可变参数的正确注释。
注释*args
的正确方法是确定某种支持的“方差长度”级别,并使用@overload
显式键入它。 值得注意的是,显式参数只能是位置参数——它们必须是__anonymous
或positional, /
。 最后一个包罗万象的可变参数@overload
处理更多 arguments 的情况。
from typing import TypeVar, Tuple, Any, overload
T = TypeVar('T')
T1 = TypeVar('T1')
T2 = TypeVar('T2')
T3 = TypeVar('T3')
# positional parameters via `, /` – Python 3.8+ only
@overload
def test(arg1: T1, /) -> Tuple[T1]: ...
# positional parameters via double underscore prefix
@overload
def test(__arg1: T1, __arg2: T2) -> Tuple[T1, T2]: ...
@overload
def test(__arg1: T1, __arg2: T2, __arg3: T3) -> Tuple[T1, T2, T3]: ...
# etc
...
# catch all variadic signature for all other cases
@overload
def test(*args: T) -> Tuple[T, ...]: ...
# implementation can use Any to simplify matching all overloads
def test(*args: Any) -> Tuple[Any, ...]:
return args
reveal_type(test(1, 2, "three")) # note: Revealed type is 'Tuple[builtins.int*, builtins.int*, builtins.str*]'
reveal_type(test(1, 2, "three", 4)) # note: Revealed type is 'builtins.tuple[builtins.object*]'
reveal_type(test(1, 2, 3, 4)) # note: Revealed type is 'builtins.tuple[builtins.int*]'
值得注意的是,虽然打包成可变参数可以键入,但解包arguments 通常不能:除了tuple
之外的任何容器都是任意长度的——例如List[int] = [1, 2, 3]
——因此没有确切的类型信息它的元素。
# unpack tuple of int, int
reveal_type(test(*(1, 2,))) # note: Revealed type is 'Tuple[builtins.int*, builtins.int*]'
# unpack list of some ints
reveal_type(test(*[1, 2,])) # note: Revealed type is 'builtins.tuple[builtins.int*]'
这可以通过TypeVarTuple
中的TypeVarTuple解决,在 Python 3.11 或前向兼容模块类型扩展中实现。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.