简化场景(游乐场):
from typing import TypeVar, reveal_type
class A: ...
class B(A): ...
class C(A): ...
T = TypeVar('T', bound=A)
def fun(*args: T) -> tuple[T, ...]: return args
# one parameter
reveal_type(fun(A())) # Revealed type is "builtins.tuple[gargs.A, ...]"
reveal_type(fun(B())) # Revealed type is "builtins.tuple[gargs.B, ...]"
reveal_type(fun(C())) # Revealed type is "builtins.tuple[gargs.C, ...]"
# multiple parameters, same type
reveal_type(fun(A(), A())) # Revealed type is "builtins.tuple[gargs.A, ...]"
reveal_type(fun(B(), B())) # Revealed type is "builtins.tuple[gargs.B, ...]"
reveal_type(fun(C(), C())) # Revealed type is "builtins.tuple[gargs.C, ...]"
# multiple parameters, different types
reveal_type(fun(A(), B())) # Revealed type is "builtins.tuple[gargs.A, ...]"
reveal_type(fun(B(), C())) # Revealed type is "builtins.tuple[gargs.A, ...]"
reveal_type(fun(C(), A())) # Revealed type is "builtins.tuple[gargs.A, ...]"
有没有办法注释
fun
来教导 mypy
fun
在后三种情况下应该返回 tuple[A, B]
、tuple[B, C]
和 tuple[C, A]
?
TypeVarTuple
的用途:
(游乐场)
from typing import TypeVarTuple
Ts = TypeVarTuple('Ts')
def fun(*args: *Ts) -> tuple[*Ts]: return args
reveal_type(fun(A())) # tuple[A]
reveal_type(fun(B())) # tuple[B]
reveal_type(fun(C())) # tuple[C]
reveal_type(fun(A(), A())) # tuple[A, A]
reveal_type(fun(B(), B())) # tuple[B, B]
reveal_type(fun(C(), C())) # tuple[C, C]
reveal_type(fun(A(), B())) # tuple[A, B]
reveal_type(fun(B(), C())) # tuple[B, C]
reveal_type(fun(C(), A())) # tuple[C, A]
一个缺点是
TypeVarTuple
还不能被绑定,所以我们必须使用一些技巧:
(游乐场)
from typing import Any, Never, Protocol, TypeVarTuple
Ts = TypeVarTuple('Ts')
class F1(Protocol):
def __call__(self, /, *args: *Ts) -> tuple[*Ts]: ...
class F2(Protocol):
def __call__(self, /, *args: A) -> Never: ...
def fun_decorator(fun: Any) -> F1 | F2:
return fun
@fun_decorator
def fun(*args: *Ts) -> tuple[*Ts]: return args
reveal_type(fun(D())) # error
reveal_type(fun(D(), A())) # error
reveal_type(fun(C(), B(), D())) # error
装饰后,
fun
具有F1 | F2
类型。两者都接受可变数量的参数,但 F2
要求其参数必须全部为 A
类型。返回类型推导为 tuple[*Ts] | Never
,本质上就是 tuple[*Ts]
。