方括号内的 **(双星/星号)和 *(星号/星号)对于 Python 3.12+ 中的类和函数声明意味着什么?

问题描述 投票:0回答:1

T, *Ts, **P
直接用在类或函数名称后面的方括号中或与
type
关键字一起使用时,它们意味着什么?

class ChildClass[T, *Ts, **P]: ...

def foo[T, *Ts, **P](arg: T) -> Callable[P, tuple[T, *Ts]]:

type vat[T, *Ts, **P] = Callable[P, tuple[T, *Ts]]

请参阅有关函数参数和参数的 ** 和 * 的补充问题:

python generics python-typing asterisk type-parameter
1个回答
0
投票
Python 3.12 与

PEP 695 相关,带来了一些 语法 它将 typing 库中的一些功能引入到语言本身的语法中。

简而言之就是每一个0-2个开始的表达式

T, *Ts, **P

一个
类型参数,它们被用作类型参数列表的参数,可用于函数,类和type
语句来创建一个
TypeAliasType
。
由 
[]
 封装的类型参数列表可以跟在 
type
 语句之后的类、函数或类型变量的名称,并将创建一个 
generic。类型检查器可以推断属性和调用的类型,例如:

class ClassA[T]: def method1(self) -> T: ... def create[T, *Ts](arg: T, *args: *Ts) -> ClassA[tuple[T, *Ts]]: ... a = create(1, 2, 3) # a inferred as Class[tuple[int, int, int]] t = a.method1() # t inferred as tuple[int, int, int]


在类型参数列表中,三个不同数量的星号具有以下含义

0-2 星号的三种不同变体区分这些类型。 函数和类的类型参数列表仅在其本地范围内定义列出的类型参数,类似于 typing.Self,它指的是 class

' 体内封装类的类型。

文档中的以下示例说明了大多数用法:

def overly_generic[ SimpleTypeVar, TypeVarWithBound: int, TypeVarWithConstraints: (str, bytes), *SimpleTypeVarTuple, **SimpleParamSpec, ]( a: SimpleTypeVar, b: TypeVarWithBound, c: Callable[SimpleParamSpec, TypeVarWithConstraints], *d: SimpleTypeVarTuple, ): ...
此外,

ParamSpec

args
kwargs
属性也可用于注释两个或仅两个以
*
**
为前缀的函数参数

def usage_with_kwargs[ SimpleTypeVar, **SimpleParamSpec, ]( c: Callable[SimpleParamSpec, SimpleTypeVar], *c_args: SimpleParamSpec.args, **c_kwargs: SimpleParamSpec.kwargs ): ...


您可能已经注意到,语法还允许在类型参数列表中使用冒号

:

,这些地址解决了 
typing.TypeVar
 的其他一些参数,允许定义类型变量的上层 
bound 类型或 约束 表明类型是类型 A 或 B 或 ...

TypeVarWithBound: int # equivalent to TypeVar("TypeVarWithBound", bound=int) TypeVarWithConstraints: (str, bytes), # equivalent to TypeVar("TypeVarWithConstraints", str, bytes)


用于类声明和

type

 语句的类型参数列表也是如此,只是在 Python 版本中 
<3.12 we have to use typing_extensions.TypeAliasType
typing.Generic
 中,前者与 
type
 语句的功能等效。 

引用

PEP 695

在 python 3.12 之前定义泛型类看起来像这样:

from typing import Generic, TypeVar _T_co = TypeVar("_T_co", covariant=True, bound=str) class ClassA(Generic[_T_co]): def method1(self) -> _T_co: ...
使用新语法,它看起来像这样,省略了直接使用 

TypeVar

 的需要。

class ClassA[T: str]: def method1(self) -> T: ...


对于

type

 声明,它是类似的:

from collections.abc import Callable type call[T, **P, *Ts] = Callable[P, tuple[T, *Ts]]
相当于

from typing import ParamSpec, TypeVarTuple, TypeVar, Unpack #, TypeAliasType # if Python >= 3.12 from typing_extensions import TypeAliasType # backport from collections.abc import Callable T = TypeVar('T') P = ParamSpec('P') Ts = TypeVarTuple("Ts") call = TypeAliasType("call", Callable[P, tuple[T, Unpack[Ts]]], type_params=(T, P, Ts))
    
© www.soinside.com 2019 - 2024. All rights reserved.