簡體   English   中英

Python可以打*(拆包)操作符嗎? 或者任何其他可變參數 function 使得所有可變參數類型都在結果類型中?

[英]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顯式鍵入它。 值得注意的是,顯式參數只能是位置參數——它們必須是__anonymouspositional, / 最后一個包羅萬象的可變參數@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 或前向兼容模塊類型擴展中實現。

另請參閱Dynamic TypeVar 以了解解決方案的一系列類型

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM