GenericAlias 对象通常是通过 抽取 一个类来创建的。 它们最常被用于 容器类,如 list 或 dict。 举例来说,list[int] 这个 GenericAlias 对象是通过附带 int 参数抽取 list 类来创建的。 GenericAlias 对象的主要目的是用于 类型标注。
备注 通常一个类只有在实现了特殊方法 class_getitem() 时才支持抽取操作。
GenericAlias 对象可作为 generic type 的代理,实现了 形参化泛型。
对于一个容器类,提供给类的 抽取 操作的参数可以指明对象所包含的元素类型。 例如,set[bytes] 可在类型标注中用来表示一个 set 中的所有元素均为 bytes 类型。
对于一个定义了 class_getitem() 但不属于容器的类,提供给类的抽取操作的参数往往会指明在对象上定义的一个或多个方法的返回值类型。 例如,正则表达式 可以被用在 str 数据类型和 bytes 数据类型上:
如果 x = re.search(‘foo’, ‘foo’),则 x 将为一个 re.Match 对象而 x.group(0) 和 x[0] 的返回值将均为 str 类型。 我们可以在类型标注中使用 GenericAlias re.Match[str] 来代表这种对象。
如果 y = re.search(b’bar’, b’bar’),(注意 b 表示 bytes),则 y 也将为一个 re.Match 的实例,但 y.group(0) 和 y[0] 的返回值将均为 bytes 类型。 在类型标注中,我们将使用 re.Match[bytes] 来代表这种形式的 re.Match 对象。
GenericAlias 对象是 types.GenericAlias 类的实例,该类也可被用来直接创建 GenericAlias 对象。
T[X, Y, …]
创建一个代表由类型 X, Y 来参数化的类型 T 的 GenericAlias,此类型会更依赖于所使用的 T。 例如,一个接受包含 float 元素的 list 的函数:
def average(values: list[float]) -> float:
return sum(values) / len(values)
另一个例子是关于 mapping 对象的,用到了 dict,泛型的两个类型参数分别代表了键类型和值类型。本例中的函数需要一个 dict,其键的类型为 str,值的类型为 int:。
def send_post_request(url: str, body: dict[str, int]) -> None:
…
内置函数 isinstance() 和 issubclass() 不接受第二个参数为GenericAlias
类型:
>>>
isinstance([1, 2], list[str])
Traceback (most recent call last):
File "", line 1, in
TypeError: isinstance() argument 2 cannot be a parameterized generic
Python 运行时不会强制执行 类型标注。 这种行为扩展到了泛型及其类型形参。 当由 GenericAlias 创建容器对象时,并不会检查容器中为元素指定的类型。 例如,以下代码虽然不被鼓励,但运行时并不会报错:
>>>
t = list[str]
t([1, 2, 3])
[1, 2, 3]
不仅如此,在创建对象的过程中,应用了参数后的泛型还会抹除类型参数:
>>>
t = list[str]
type(t)
l = t()
type(l)
在泛型上调用 repr() 或 str() 会显示应用参数之后的类型:
>>>
repr(list[int])
'list[int]'
str(list[int])
'list[int]'
调用泛型容器的 getitem() 方法将引发异常以防出现 dict[str][str] 之类的错误:
>>>
dict[str][str]
Traceback (most recent call last):
File "", line 1, in
TypeError: There are no type variables left in dict[str]
不过,当使用了 类型变量 时这种表达式是无效的。 索引必须有与 GenericAlias 对象的 args 中的类型变量条目数量相当的元素。
>>>
from typing import TypeVar
Y = TypeVar('Y')
dict[str, Y][int]
dict[str, int]
下列标准库类支持形参化的泛型。 此列表并不是详尽无遗的。
tuple
list
dict
set
frozenset
type
collections.deque
collections.defaultdict
collections.OrderedDict
collections.Counter
collections.ChainMap
collections.abc.Awaitable
collections.abc.Coroutine
collections.abc.AsyncIterable
collections.abc.AsyncIterable
collections.abc.AsyncGenerator
collections.abc.Iterable
collections.abc.Iterator
collections.abc.Generator
collections.abc.Reversible
collections.abc.Container
collections.abc.Collection
collections.abc.Callable
collections.abc.Set
collections.abc.MutableSet
collections.abc.Mapping
collections.abc.MutableMapping
collections.abc.Sequence
collections.abc.MutableSequence
collections.abc.ByteString
collections.abc.MappingView
collections.abc.KeysView
collections.abc.ItemsView
collections.abc.ValuesView
contextlib.AbstractContextManager
contextlib.AbstractAsyncContextManager
dataclasses.Field
functools.cached_property
functools.partialmethod
os.PathLike
queue.LifoQueue
queue.Queue
queue.PriorityQueue
queue.SimpleQueue
re.Pattern
re.Match
shelve.BsdDbShelf
shelve.DbfilenameShelf
shelve.Shelf
types.MappingProxyType
weakref.WeakKeyDictionary
weakref.WeakMethod
weakref.WeakSet
weakref.WeakValueDictionary
GenericAlias 对象的特殊属性
应用参数后的泛型都实现了一些特殊的只读属性:
genericalias.origin
本属性指向未应用参数之前的泛型类:
>>>
list[int].__origin__
genericalias.__args__
该属性是传给泛型类的原始 class_getitem() 的泛型所组成的 tuple (长度可能为 1):
>>>
dict[str, list[int]].__args__
(, list[int])
genericalias.__parameters__
该属性是延迟计算出来的一个元组(可能为空),包含了 args 中的类型变量。
>>>
from typing import TypeVar
T = TypeVar('T')
list[T].__parameters__
(~T,)
备注 带有参数 typing.ParamSpec 的 GenericAlias 对象,在类型替换后其 parameters 可能会不准确,因为 typing.ParamSpec 主要用于静态类型检查。
genericalias.unpacked
3.11 新版功能.
参见
PEP 484 —— 类型注解
介绍 Python 中用于类型标注的框架。
PEP 585 - 标准多项集中的类型提示泛型
介绍了对标准库类进行原生形参化的能力,只要它们实现了特殊的类方法 class_getitem()。
泛型(Generic), 用户自定义泛型 和 typing.Generic
有关如何实现可在运行时被形参化并能被静态类型检查器所识别的泛用类的文档。
3.9 新版功能.
联合对象包含了在多个 类型对象 上执行 | (按位或) 运算后的值。 这些类型主要用于 类型标注。与 typing.Union 相比,联合类型表达式可以实现更简洁的类型提示语法。
X | Y | …
定义包含了 X、Y 等类型的 union 对象。X | Y 表示 X 或 Y。相当于typing.Union[X, Y]
。比如以下函数的参数应为类型 int 或 float :
def square(number: int | float) -> int | float:
return number ** 2
union_object == other
union 对象可与其他 union 对象进行比较。详细结果如下:
多次组合的结果会平推:
(int | str) | float == int | str | float
冗余的类型会被删除:
int | str | int == int | str
在相互比较时,会忽略顺序:
int | str == str | int
与 typing.union 兼容:
int | str == typing.Union[int, str]
Optional 类型可表示为与 None 的组合。
str | None == typing.Optional[str]
isinstance(obj, union_object)
issubclass(obj, union_object)
isinstance() 和 issubclass() 也支持 union 对象:
>>>
isinstance("", int | str)
True
但不能使用包含 parameterized generics 的 union 对象:
isinstance(1, int | list[int])
Traceback (most recent call last):
File “”, line 1, in
TypeError: isinstance() argument 2 cannot contain a parameterized generic
union 对象构成的用户类型可以经由 types.UnionType 访问,并可用于 isinstance() 检查。 而不能由类型直接实例化为对象:
>>>
import types
isinstance(int | str, types.UnionType)
True
types.UnionType()
Traceback (most recent call last):
File "", line 1, in
TypeError: cannot create 'types.UnionType' instances
备注 为了支持 X | Y 语法,类型对象加入了 or() 方法。若是元类已实现了 or(),union 也可以覆盖掉:
>>>
class M(type):
def __or__(self, other):
return "Hello"
class C(metaclass=M):
pass
C | int
'Hello'
int | C
int | __main__.C
参见 PEP 604 —— 提出了 X | Y 语法和 union 类型。
3.10 新版功能.