可以在 Python 中输入 *解包运算符吗?或者任何其他可变参数 args 函数,使得所有可变参数类型都在结果类型中?

问题描述

使用类型存根,我想知道是否可以在 Python 中表达一种类型,允许您为任意数量的参数正确键入:

def test(*args):
  return args

乍一看,我带着:

T = TypeVar('T')
def test(*args: T) -> Tuple[T,...]:
  return args

但这当然只会正确输入第一个 T。

是为所有参数编写覆盖的唯一可能方法吗?

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,arg3: T3,arg4: T4) -> Tuple[T1,T3,T4]: ...
# etc
def test(*args: Any) -> Tuple[Any,...]:
  return args

这也不完整,因为它没有携带足够的类型信息来键入:

x: Tuple[int,int,str] = test(*[1,2,"4"])

解决方法

TLDR:@overload 是目前唯一可行的方式来注释某些级别的差异。 PEP 646 -- Variadic Generics 是启用可变参数正确注释的提案草案。


注释 *args 的正确方法是确定某种支持的“方差长度”级别,并使用 @overload 显式键入它。值得注意的是,显式参数只能是位置参数——它们必须是 __anonymouspositional,/。最后一个包罗万象的可变参数 @overload 处理更多参数的情况。

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]: ...
@overload
def test(*args: T) -> Tuple[T,...]: ...
# etc
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,"three",4))  # note: Revealed type is 'builtins.tuple[builtins.object*]'
reveal_type(test(1,3,4))        # note: Revealed type is 'builtins.tuple[builtins.int*]'

值得注意的是,虽然打包可以输入可变参数,但解包参数通常不能:任何容器,但tuple是任意长度——例如List[int] = [1,3] – 因此没有其元素的确切类型信息。

# unpack tuple of int,int
reveal_type(test(*(1,)))  # note: Revealed type is 'Tuple[builtins.int*,builtins.int*]'
# unpack list of some ints
reveal_type(test(*[1,]))  # note: Revealed type is 'builtins.tuple[builtins.int*]'

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...