本文由 大侠(AhcaoZhu)原创,转载请声明。
链接: https://blog.csdn.net/Ahcao2008
一图看懂 typing_extensions 模块:允许在旧版Python上启用、实验新的类型系统特性,资料整理+笔记(大全)
- 🧊摘要
- 🧊模块图
- 🧊类关系图
- 🧊模块全展开
- ☘️【typing_extensions】
- 🔵统计
- 🔵常量
- 🔵模块
- 🔵函数
- 🌿17 _check_generic(cls, parameters, elen=<object object at 0x000001F281BD6FF0>)
- 🌿18 _should_collect_from_parameters(t)
- 🌿19 _collect_type_vars(types, typevar_types=None)
- 🌿20 final(f)
- 🌿21 IntVar(name)
- 🌿22 _overload_dummy(*args, **kwds)
- 🌿23 overload(func)
- 🌿24 get_overloads(func)
- 🌿25 clear_overloads()
- 🌿26 NewType(name, tp)
- 🌿27 _get_protocol_attrs(cls)
- 🌿28 _is_callable_members_only(cls)
- 🌿29 _maybe_adjust_parameters(cls)
- 🌿30 _no_init(self, *args, **kwargs)
- 🌿31 runtime_checkable(cls)
- 🌿32 runtime_checkable(cls)
- 🌿33 _check_fails(cls, other)
- 🌿34 _dict_new(*args, **kwargs)
- 🌿35 _typeddict_new(*args, total=True, **kwargs)
- 🌿36 is_typeddict(tp)
- 🌿37 assert_type(__val, __typ)
- 🌿38 _strip_extras(t)
- 🌿39 get_type_hints(obj, globalns=None, localns=None, include_extras=False)
- 🌿40 get_origin(tp)
- 🌿41 get_args(tp)
- 🌿42 _concatenate_getitem(self, parameters)
- 🌿43 _is_unpack(obj)
- 🌿44 reveal_type(__obj: ~T) -> ~T
- 🌿45 assert_never(__arg: typing_extensions.Never) -> typing_extensions.Never
- 🌿46 dataclass_transform(*, eq_default: bool = True, order_default: bool = False, kw_only_default: bool = False, frozen_default: bool = False, field_specifiers: Tuple[Union[Type[Any], Callable[..., Any]], ...] = (), **kwargs: Any) -> Callable[[~T], ~T]
- 🌿47 override(__arg: ~_F) -> ~_F
- 🌿48 deprecated(__msg: str, *, category: Union[Type[Warning], NoneType] = <class 'DeprecationWarning'>, stacklevel: int = 1) -> Callable[[~_T], ~_T]
- 🌿49 _caller()
- 🌿50 _make_nmtuple(name, types, module, defaults=())
- 🌿51 NamedTuple(__typename, __fields=None, **kwargs)
- 🌿52 _namedtuple_mro_entries(bases)
- 🔵类
- 🌿53 type
- 🌿54 typing_extensions._AnyMeta
- 🌿55 typing_extensions.An
- 🌿56 typing_extensions._FinalForm
- 🌿57 typing_extensions._LiteralForm
- 🌿58 str
- 🌿59 typing_extensions._ProtocolMeta
- 🌿60 typing_extensions.Protocol
- 🌿61 typing_extensions.SupportsIndex
- 🌿62 typing_extensions._TypedDictMeta
- 🌿63 typing_extensions.TypedDict
- 🌿64 typing_extensions._AnnotatedAlias
- 🌿65 typing_extensions.Annotated
- 🌿66 typing._GenericAlias
- 🌿67 typing._GenericAlias
- 🌿68 typing_extensions._TypeAliasForm
- 🌿69 typing_extensions._DefaultMixin
- 🌿70 typing.TypeVar
- 🌿71 typing_extensions._Immutable
- 🌿72 typing_extensions.ParamSpecArgs
- 🌿73 typing_extensions.ParamSpecKwargs
- 🌿74 typing_extensions.ParamSpec
- 🌿75 typing_extensions._ConcatenateGenericAlias
- 🌿76 typing_extensions._ConcatenateForm
- 🌿77 typing_extensions._TypeGuardForm
- 🌿78 typing_extensions._SpecialForm
- 🌿79 typing_extensions._RequiredForm
- 🌿80 typing_extensions._UnpackAlias
- 🌿81 typing_extensions._UnpackForm
- 🌿82 typing_extensions.TypeVarTuple
- 🌿83 typing_extensions._NamedTupleMeta
- 🌿84 typing_extensions.NamedTuple
- 🔵私有或局部
- 🔵剩余
- ☘️【abc】
- ☘️【collections】
- ☘️【functools】
- ☘️【inspect】
- ☘️【operator】
- ☘️【sys】
- ☘️【types】
- ☘️【typing】
- ☘️【warnings】
🧊摘要
🧊模块图
typing_extensions
◆abc
◆collections
◆functools
◆inspect
◆operator
◆sys
◆types
◆typing
◆warnings
🧊类关系图
◆object
◆dict
typing_extensions.TypedDict
◆list
◆functools._HashedSeq
typing_extensions.ParamSpec
typing_extensions._ConcatenateGenericAlias
◆type
◆abc.ABCMeta
typing_extensions._ProtocolMeta
typing_extensions._AnyMeta
typing_extensions._NamedTupleMeta
typing_extensions._TypedDictMeta
◆typing._Final
◆typing._GenericAlias
◆typing._VariadicGenericAlias
typing_extensions._AnnotatedAlias
typing_extensions._UnpackAlias
◆typing._SpecialForm
typing_extensions._ConcatenateForm
typing_extensions._FinalForm
typing_extensions._LiteralForm
typing_extensions._RequiredForm
typing_extensions._TypeAliasForm
typing_extensions._TypeGuardForm
typing_extensions._UnpackForm
typing_extensions._SpecialForm
typing_extensions.Annotated
typing_extensions.NamedTuple
typing_extensions.Protocol
typing_extensions.SupportsIndex
typing_extensions._DefaultMixin
typing_extensions.TypeVarTuple
typing_extensions._Immutable
typing_extensions.ParamSpecArgs
typing_extensions.ParamSpecKwargs
typing_extensions.An
🧊模块全展开
☘️【typing_extensions】
🔵统计
🔵常量
🌿bool
🌿tuple
🌿list
🔵模块
🌿7 abc
🌿8 collections
🌿9 functools
🌿10 inspect
🌿11 operator
🌿12 sys
🌿13 types
🌿14 typing
🌿15 warnings
🌿16 types
🔵函数
🌿17 _check_generic(cls, parameters, elen=<object object at 0x000001F281BD6FF0>)
检查泛型cls(内部助手)参数的正确计数。在计数不匹配的情况下,这会给出一个很好的错误消息。
🌿18 _should_collect_from_parameters(t)
🌿19 _collect_type_vars(types, typevar_types=None)
按首次出现的顺序(字典顺序)收集类型中包含的所有类型变量。例如:
_collect_type_vars((T, List[S, T])) == (T, S)
🌿20 final(f)
此装饰器可用于向类型检查器指示不能重写已装饰的方法,并且不能对已装饰的类进行子类化。
例如:
class Base:
@final
def done(self) -> None:
...
class Sub(Base):
def done(self) -> None: # 类型检查器报告的错误
...
@final
class Leaf:
...
class Other(Leaf): # 类型检查器报告的错误
...
没有对这些属性进行运行时检查。装饰器将被装饰对象的 ``__final__`` 属性设置为``True``,以允许运行时自省。
🌿21 IntVar(name)
🌿22 _overload_dummy(*args, **kwds)
当@overload被调用时触发的Helper。
🌿23 overload(func)
重载函数/方法的装饰器。
🌿24 get_overloads(func)
将*func*的所有定义重载作为一个序列返回。
🌿25 clear_overloads()
清除注册表中的所有过载。
🌿26 NewType(name, tp)
NewType创建简单的唯一类型,运行时开销几乎为零。
静态类型检查器认为NewType(name, tp)是tp的子类型。
在运行时,NewType(name, tp)返回一个虚拟函数,该函数只返回其参数。
用法:
UserId = NewType('UserId', int)
def name_by_id(user_id: UserId) -> str:
...
UserId('user') # Fails type check
name_by_id(42) # Fails type check
name_by_id(UserId(42)) # OK
num = UserId(5) + 1 # type: int
🌿27 _get_protocol_attrs(cls)
🌿28 _is_callable_members_only(cls)
🌿29 _maybe_adjust_parameters(cls)
协议中使用的Helper函数。
该函数的内容与在CPython主分支上创建子类 typing.Generic.__init_subclass__ 中的逻辑非常相似。
🌿30 _no_init(self, *args, **kwargs)
🌿31 runtime_checkable(cls)
将协议类标记为运行时协议,以便它可以与isinstance()和issubclass()一起使用。
如果应用于非协议类,则引发TypeError。
这允许进行与集合中的一次性检查非常相似的简单结构检查。例如hashhable。
🌿32 runtime_checkable(cls)
将协议类标记为运行时协议,以便它可以与isinstance()和issubclass()一起使用。
如果应用于非协议类,则引发TypeError。
这允许进行与集合中的一次性检查非常相似的简单结构检查。例如hashhable。
🌿33 _check_fails(cls, other)
🌿34 _dict_new(*args, **kwargs)
🌿35 _typeddict_new(*args, total=True, **kwargs)
🌿36 is_typeddict(tp)
检查注释是否为TypedDict类。
例如:
class Film(TypedDict):
title: str
year: int
is_typeddict(Film) # => True
is_typeddict(Union[list, str]) # => False
🌿37 assert_type(__val, __typ)
断言(对类型检查器)该值为给定类型。
当类型检查器遇到对assert type()的调用时,如果值不是指定的类型,它会发出一个错误:
def greet(name: str) -> None:
assert_type(name, str) # ok
assert_type(name, int) # type checker error
#类型检查器错误在运行时,这将返回第一个参数不变,否则什么都不做。
🌿38 _strip_extras(t)
从给定类型中标注的、必需的和非必需的条带。
🌿39 get_type_hints(obj, globalns=None, localns=None, include_extras=False)
返回对象的类型提示。
这通常与obj.__annotations__相同。但它处理编码为字符串字面值的转发引用,如果设置了默认值为None,
则添加Optional[t]并递归地替换所有的 'Annotated[T, ...]', 'Required[T]' 或 'NotRequired[T]' 带有 'T'(除非'include_extras=True')。
参数可以是模块、类、方法或函数。注释作为字典返回。对于类,注释也包括继承的成员。
如果参数不是可以包含注释的类型,则引发TypeError;如果不存在注释,则返回空字典。
注意- globalns和localns的行为是违反直觉的(除非你熟悉eval()和exec()的工作方式)。搜索顺序是先本地搜索,再全局搜索。
-如果没有传递dict参数,则尝试使用来自obj的全局变量(或相应模块的类的全局变量),这些也被用作局部变量。如果对象没有全局变量,则使用空字典。
-如果传入一个dict参数,它将同时用于全局变量和局部变量。
-如果传递两个dict参数,它们分别指定全局变量和局部变量。
🌿40 get_origin(tp)
获取类型的未下标版本。
它支持泛型类型,Callable, Tuple, Union, Literal, Final, ClassVar和Annotated。
对于不支持的类型返回None。例如:
get_origin(Literal[42]) is Literal
get_origin(int) is None
get_origin(ClassVar[int]) is ClassVar
get_origin(Generic) is Generic
get_origin(Generic[T]) is Generic
get_origin(Union[T, int]) is Union
get_origin(List[Tuple[T, T]][int]) == list
get_origin(P.args) is P
🌿41 get_args(tp)
获取已执行所有替换的类型参数。
对于联合,执行联合构造函数使用的基本简化。
示例:
get_args(Dict[str, int]) == (str, int)
get_args(int) == ()
get_args(Union[int, Union[T, int], str][int]) == (int, str)
get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int])
get_args(Callable[[], T][int]) == ([], int)
🌿42 _concatenate_getitem(self, parameters)
🌿43 _is_unpack(obj)
🌿44 reveal_type(__obj: ~T) -> ~T
显示变量的推断类型。
当静态类型检查器遇到对 ``reveal_type()`` 的调用时,它将发出参数的推断类型:
x: int = 1
reveal_type(x)
在本例中运行静态类型检查器(例如 ``mypy``)将产生类似于'Revealed type is "builtins.int"'的输出。
在运行时,该函数打印实参的运行时类型并原样返回。
🌿45 assert_never(__arg: typing_extensions.Never) -> typing_extensions.Never
向类型检查器断言一行代码不可达。
示例:
def int_or_str(arg: int | str) -> None:
match arg:
case int():
print("It's an int")
case str():
print("It's a str")
case _:
assert_never(arg)
如果类型检查器发现assert_never()的调用是可达的,它将发出一个错误。
在运行时,这将在调用时抛出异常。
🌿46 dataclass_transform(*, eq_default: bool = True, order_default: bool = False, kw_only_default: bool = False, frozen_default: bool = False, field_specifiers: Tuple[Union[Type[Any], Callable[…, Any]], …] = (), **kwargs: Any) -> Callable[[~T], ~T]
将函数、类或元类标记为提供类似数据类的行为的修饰符。
示例:
from typing_extensions import dataclass_transform
_T = TypeVar("_T")
# Used on a decorator function
@dataclass_transform()
def create_model(cls: type[_T]) -> type[_T]:
...
return cls
@create_model
class CustomerModel:
id: int
name: str
# Used on a base class
@dataclass_transform()
class ModelBase: ...
class CustomerModel(ModelBase):
id: int
name: str
# Used on a metaclass
@dataclass_transform()
class ModelMeta(type): ...
class ModelBase(metaclass=ModelMeta): ...
class CustomerModel(ModelBase):
id: int
name: str
在这个例子中定义的每个 ``CustomerModel`` 类现在的行为类似于用``@dataclasses.dataclass``装饰。
例如,类型检查器将合成一个``__init__``方法。
这个装饰器的参数可以用来自定义这个行为:
- ``eq_default``指示如果调用者省略``eq``参数,则假设``eq``参数为True还是False。
- ``order_default`` 指示如果调用者省略 ``order`` 参数,则该参数是假定为True还是False。
- ``kw_only_default`` 表示如果调用者省略 ``kw_only`` 参数,则该参数是假定为True还是False。
- ``frozen_default`` 指示如果调用者省略 ``frozen`` 参数,则该参数是假定为True还是False。
- ``field_specifiers`` 指定描述字段的支持类或函数的静态列表,类似于 ``dataclasses.field()``。
在运行时,此装饰器将其参数记录在被装饰对象的 ``__dataclass_transform__`` 属性中。
请参阅PEP 681了解详细信息。
🌿47 override(__arg: ~_F) -> ~_F
指示一个方法打算覆盖基类中的一个方法。
用法:
class Base:
def method(self) -> None: ...
pass
class Child(Base):
@override
def method(self) -> None:
super().method()
当这个装饰器应用于一个方法时,类型检查器将验证它是否覆盖了基类上同名的方法。
这有助于防止在没有对子类进行等效更改的情况下更改基类时可能发生的错误。
没有对这些属性进行运行时检查。装饰器将被装饰对象上的 ``__override__`` 属性设置为``True``,以允许运行时自省。
请参阅PEP 698了解详细信息。
🌿48 deprecated(__msg: str, *, category: Union[Type[Warning], NoneType] = <class ‘DeprecationWarning’>, stacklevel: int = 1) -> Callable[[~_T], ~_T]
表明类、函数或重载已弃用。
用法:
@deprecated("Use B instead")
class A:
pass
@deprecated("Use g instead")
def f():
pass
@overload
@deprecated("int support is deprecated")
def g(x: int) -> int: ...
@overload
def g(x: str) -> int: ...
当此装饰器应用于对象时,类型检查器将生成关于已弃用对象使用情况的诊断。
没有发出运行时警告。装饰器设置了 ``__deprecated__`` 属性设置为传递给装饰器的弃用消息。
如果应用于重载,该装饰器必须位于 ``@overload`` 装饰器之后,才能使该属性存在于由``get_overloads()``返回的重载中。
参见PEP 702了解详细信息。
🌿49 _caller()
🌿50 _make_nmtuple(name, types, module, defaults=())
🌿51 NamedTuple(__typename, __fields=None, **kwargs)
namedtuple的类型化版本。
Python版本>= 3.6中的用法:
class Employee(NamedTuple):
name: str
id: int
这相当于:
Employee = collections.namedtuple('Employee', ['name', 'id'])
结果类具有额外的 __annotations__ 和 _field_types 属性,给出了将字段名称映射到类型的有序字典。
应该优先使用注释,而保留字段类型以保持PEP 526之前的兼容性。
(字段名在fields属性中,它是namedtuple API的一部分。)
Employee = NamedTuple('Employee', name=str, id=int)
在Python版本<= 3.5中使用:
Employee = NamedTuple('Employee', [('name', str), ('id', int)])
🌿52 _namedtuple_mro_entries(bases)
🔵类
🌿53 type
type(object_or_name, bases, dict)
type(object) -> 对象的类型
type(name, bases, dict) -> a new type
method
返回类型的方法解析顺序。
🌿54 typing_extensions._AnyMeta
🌿55 typing_extensions.An
指示非约束类型的特殊类型。
—Any与所有类型兼容。
-任何被认为拥有所有方法的人。
-所有值都假定为Any的实例。
请注意,从静态类型检查器的角度来看,上述所有语句都是正确的。在运行时,Any不应与实例检查一起使用。
🌿56 typing_extensions._FinalForm
🌿57 typing_extensions._LiteralForm
🌿58 str
🌿59 typing_extensions._ProtocolMeta
🌿60 typing_extensions.Protocol
协议类的基类。
协议类定义为:
class Proto(Protocol):
def meth(self) -> int:
...
此类类主要用于识别结构子类型(静态duck-typing)的静态类型检查器,例如:
class C:
def meth(self) -> int:
return 0
def func(x: Proto) -> int:
return x.meth()
func(C()) # 通过静态类型检查
请参阅PEP 544了解详细信息。
装饰的协议类 @typing_extensions.runtime作为一种简单的运行时协议,只检查给定属性的存在,忽略它们的类型签名。
协议类可以是泛型的,它们定义为:
class GenProto(Protocol[T]):
def meth(self) -> T:
...
🌿61 typing_extensions.SupportsIndex
🌿62 typing_extensions._TypedDictMeta
🌿63 typing_extensions.TypedDict
一个简单类型的名称空间。
在运行时,它相当于一个普通的字典。
TypedDict创建了一个字典类型,该类型期望它的所有实例都有一组键,每个键都与一个一致类型的值相关联。
在运行时不检查此期望,而仅由类型检查器强制执行。
用法:
class Point2D(TypedDict):
x: int
y: int
label: str
a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK
b: Point2D = {'z': 3, 'label': 'bad'} # 类型检查失败
assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first')
类型信息可以通过 Point2D.__annotations__ 词典,Point2D.__required_keys__,Point2D.__optional_keys__ 访问。
TypedDict支持两种额外的等价形式:
Point2D = TypedDict('Point2D', x=int, y=int, label=str)
Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str})
类语法仅在Python 3.6+中支持,而其他两种语法形式适用于Python 2.7和3.2+。
🌿64 typing_extensions._AnnotatedAlias
带注释类型的运行时表示。
其核心是 'Annotated[t, dec1, dec2, ...]' 是带有额外注释的类型't'的别名。
别名的行为类似于普通的类型别名,实例化与实例化底层类型相同,将其绑定到类型也是相同的。
method
🌿65 typing_extensions.Annotated
向类型添加特定于上下文的元数据。
示例: Annotated[int, runtime_check.Unsigned]向假设的运行时检查模块表明此类型是无符号整型。
此类型的所有其他消费者都可以忽略此元数据并将此类型视为int。
Annotated的第一个参数必须是有效类型(并且将位于 __origin__ 字段中),其余参数作为元组保存在 __extra__ 字段中。
细节:
- 使用少于两个参数调用 `Annotated` 是错误的。
- 嵌套注释被平面化:
Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3]
- 实例化一个注释类型相当于实例化底层类型:
Annotated[C, Ann1](5) == C(5)
- Annotated可以用作泛型类型别名:
Optimized = Annotated[T, runtime.Optimize()]
Optimized[int] == Annotated[int, runtime.Optimize()]
OptimizedList = Annotated[List[T], runtime.Optimize()]
OptimizedList[int] == Annotated[List[int], runtime.Optimize()]
🌿66 typing._GenericAlias
内部API的中心部分。
这表示带有类型参数'params'的'origin'类型的泛型版本。
这些别名有两种:用户定义的和特殊的。特殊的是围绕内置集合和collections.abc中的abc的包装。
这些必须始终设置“name”。如果'inst'为False,则不能实例化别名,这是通过例如 typing.List 和 typing.Dict 来使用的。
method
🌿67 typing._GenericAlias
内部API的中心部分。
这表示带有类型参数'params'的'origin'类型的泛型版本。
这些别名有两种:用户定义的和特殊的。特殊的是围绕内置集合和collections.abc中的abc的包装。
这些必须始终设置“name”。如果'inst'为False,则不能实例化别名,这是通过例如 typing.List 和 typing.Dict 来使用的。
method
🌿68 typing_extensions._TypeAliasForm
🌿69 typing_extensions._DefaultMixin
Mixin for TypeVarLike默认值。
🌿70 typing.TypeVar
类型变量
🌿71 typing_extensions._Immutable
Mixin表示该对象不应该被复制。
🌿72 typing_extensions.ParamSpecArgs
ParamSpec对象的参数。
给定一个ParamSpec对象P, P.args 是ParamSpecArgs的一个实例。
ParamSpecArgs对象有一个指向它们的ParamSpec:
P.args.__origin__ is P
此类型用于运行时自省,对静态类型检查器没有特殊意义。
🌿73 typing_extensions.ParamSpecKwargs
ParamSpec对象的参数。
给定一个ParamSpec对象P, P.kwargs是ParamSpecKwargs的一个实例。
ParamSpecKwargs对象有一个指向它们的ParamSpec:
P.kwargs.__origin__ is P
此类型用于运行时自省,对静态类型检查器没有特殊意义。
🌿74 typing_extensions.ParamSpec
参数规格变量。
用法:
P = ParamSpec('P')
参数说明变量的存在主要是为了静态类型检查器的好处。
它们用于将一个可调用对象的参数类型转发给另一个可调用对象,这是一种在高阶函数和装饰器中常见的模式。
它们仅在 ``Concatenate`` 或 ``Callable`` 的第一个参数中使用时有效。
在Python 3.10及更高版本中,它们也在运行时的用户定义泛型中得到支持。
有关泛型类型的更多信息,请参阅泛型类。注释decorator的示例:
T = TypeVar('T')
P = ParamSpec('P')
def add_logging(f: Callable[P, T]) -> Callable[P, T]:
'''A type-safe decorator to add logging to a function.'''
def inner(*args: P.args, **kwargs: P.kwargs) -> T:
logging.info(f'{f.__name__} was called')
return f(*args, **kwargs)
return inner
@add_logging
def add_two(x: float, y: float) -> float:
'''Add two numbers together.'''
return x + y
用covariant=True或contravant =True定义的参数说明变量可用于声明协变或逆变泛型类型。
这些关键字参数是有效的,但它们的实际语义尚未确定。参见PEP 612了解详细信息。
参数说明变量可以自省。例如:
P.__name__ == 'T'
P.__bound__ == None
P.__covariant__ == False
P.__contravariant__ == False
注意,只有在全局作用域中定义的参数说明变量才能被pickle。
property
🌿75 typing_extensions._ConcatenateGenericAlias
🌿76 typing_extensions._ConcatenateForm
🌿77 typing_extensions._TypeGuardForm
🌿78 typing_extensions._SpecialForm
<member '__doc__' of '_SpecialForm' objects>
🌿79 typing_extensions._RequiredForm
🌿80 typing_extensions._UnpackAlias
🌿81 typing_extensions._UnpackForm
🌿82 typing_extensions.TypeVarTuple
类型变量元组。
用法:
Ts = TypeVarTuple('Ts')
就像普通类型变量是单个类型(如``int``)的替身一样,类型变量*tuple*是*元组*类型(如 ``Tuple[int, str]``)的替身。
类型变量元组可以在“泛型”声明中使用。考虑下面的例子:
class Array(Generic[*Ts]): ...
这里的 ``Ts`` 类型变量元组的行为类似于``tuple[T1, T2]``,其中 ``T1`` 和 ``T2`` 是类型变量。
要使用这些类型变量作为 ``Array`` 的类型参数,我们必须使用星号操作符 ``*Ts`` 来 *unpack* 类型变量元组。
然后,``Array`` 的签名就像我们简单地写了 ``class Array(Generic[T1, T2]): ...`` 一样。
然而,与 ``Generic[T1, T2]`` 相反,``Generic[*Shape]`` 允许我们使用任意数量的类型参数对类进行参数化。
类型变量元组可以用在普通的 ``TypeVar`` 可以用的任何地方。这包括如上所示的类定义,以及函数签名和变量注释:
class Array(Generic[*Ts]):
def __init__(self, shape: Tuple[*Ts]):
self._shape: Tuple[*Ts] = shape
def get_shape(self) -> Tuple[*Ts]:
return self._shape
shape = (Height(480), Width(640))
x: Array[Height, Width] = Array(shape)
y = abs(x) # Inferred type is Array[Height, Width]
z = x + x # ... is Array[Height, Width]
x.get_shape() # ... is tuple[Height, Width]