Skip to content
Advertisement

Can the * (unpacking) operator be typed in Python? Or any other variadic args function such that all variadic types are in the result type?

Working with type stubs, I’m wondering if it’s possible to express a type in Python that allows you to type this correctly for any number of arguments:

def test(*args):
  return args

At first glance, I came with:

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

But this of course will only type correctly the first T.

Is the only possible way to write the overrides for all 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

This is not complete either, since it does not carry enough type information to type something like:

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

Advertisement

Answer

This can solved through TypeVarTuple from PEP646, implemented in Python 3.11 or forward compat module typing-extensions.

See this analog example:

from __future__ import annotations

from typing import Any, Callable, Generic
from typing_extensions import TypeVarTuple, Unpack  # typing_extensions only needed for Python < 3.11

Ts = TypeVarTuple("Ts")

class Signal(Generic[Unpack[Ts]]):
    def add_callback(self, func: Callable[[Unpack[Ts]], Any]) -> None:
        ...

    def emit(self, *args: Unpack[Ts]) -> None:
        ...

def callback(a: int, b: str) -> None:
    ...

def callback_bad(a: str) -> None:
    ...

sig: Signal[int, str] = Signal()
sig.add_callback(callback)  # Good lint
sig.add_callback(callback_bad)  # Bad lint

sig.emit(1223, "foo")  # Good lint
sig.emit("bar")  # Bad lint

Also see Dynamic TypeVar for a sequence of types for a solution.

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement