# 26.1. `typing` —— 支持类型提示

版本3.5中的新功能。

源代码： Lib/typing.py

此模块支持由 PEP 484指定的类型提示。The most fundamental support consists of the type `Any`, `Union`, `Tuple`, `Callable`, `TypeVar`, and `Generic`. 有关完整规格，请参阅 PEP 484。有关类型提示的简化介绍，请参见 PEP 483。

下面的函数接受和返回一个字符串，并注释如下：

    def greeting(name: str) -> str:
        return 'Hello ' + name

在函数`greeting`中，参数`name`应为`str`类型，返回类型`str`。子类型被接受为参数。

## 26.1.1.类型别名

通过将类型分配给别名来定义类型别名。在此示例中，`Vector`和`List[float]`将被视为可互换的同义词：

    from typing import List
    Vector = List[float]

    def scale(scalar: float, vector: Vector) -> Vector:
        return [scalar * num for num in vector]

    # typechecks; a list of floats qualifies as a Vector.
    new_vector = scale(2.0, [1.0, -4.2, 5.4])

类型别名可用于简化复杂类型签名。例如：

    from typing import Dict, Tuple, List

    ConnectionOptions = Dict[str, str]
    Address = Tuple[str, int]
    Server = Tuple[Address, ConnectionOptions]

    def broadcast_message(message: str, servers: List[Server]) -> None:
        ...

    # The static type checker will treat the previous type signature as
    # being exactly equivalent to this one.
    def broadcast_message(
            message: str,
            servers: List[Tuple[Tuple[str, int], Dict[str, str]]]) -> None:
        ...

## 26.1.2.NewType

使用`NewType`帮助函数创建不同类型：

    from typing import NewType

    UserId = NewType('UserId', int)
    some_id = UserId(524313)

静态类型检查器将把新类型视为原始类型的子类。这有助于捕获逻辑错误：

    def get_user_name(user_id: UserId) -> str:
        ...

    # typechecks
    user_a = get_user_name(UserId(42351))

    # does not typecheck; an int is not a UserId
    user_b = get_user_name(-1)

您仍然可以对`UserId`类型的变量执行所有`int`操作，但结果始终为`int`类型。这样，您可以在`int`中传递`UserId`，但会阻止您以无效方式意外创建`UserId`：

    # 'output' is of type 'int', not 'UserId'
    output = UserId(23413) + UserId(54341)

注意，这些检查仅由静态类型检查器强制执行。在运行时，语句`Derived = NewType('Derived', Base)`使`Derived`成为一个函数，该函数立即返回传递给它的任何参数。这意味着表达式`Derived(some_value)`不会创建新类或引入超出常规函数调用的任何开销。

更准确地说，在运行时刻，表达式`some_value is Derived(some_value)`永远为真。

这也意味着不可能创建`Derived`的子类型，因为它是运行时的标识函数，而不是实际类型。类似地，不可能基于`Derived`类型创建另一个`NewType`：

    from typing import NewType

    UserId = NewType('UserId', int)

    # Fails at runtime and does not typecheck
    class AdminUserId(UserId): pass

    # Also does not typecheck
    ProUserId = NewType('ProUserId', UserId)

有关详细信息，请参阅 PEP 484。

注意

回想一下，类型别名的使用声明两种类型彼此等效。执行`别名 = 原始会使静态类型检查器将`Alias`视为到`Original``当您想要简化复杂类型签名时，这是非常有用的。

相比之下，`NewType`声明一种类型为另一个类型的子类型。执行`导出 = NewType（'Derived'，NewType（'Derived'， Original）静态类型检查器将`Derived`视为`Original`的子类，这意味着不能使用类型`Original`的值在期望类型为`Derived`的地方。`当您希望以最小的运行时成本防止逻辑错误时，这是​​有用的。

## 26.1.3.可调用

期望特定签名的回调函数的框架可以使用`Callable [[Arg1Type， Arg2Type]，Arg2Type]， ReturnType]`

例如：

    from typing import Callable

    def feeder(get_next_item: Callable[[], str]) -> None:
        # Body

    def async_query(on_success: Callable[[int], None],
                    on_error: Callable[[int, Exception], None]) -> None:
        # Body

可以通过用类型hint中的参数列表替换字面值省略来声明可调用的返回类型，而不指定调用声明：hint：`Callable [...， ReturnType]``None`作为类型提示是一种特殊情况，并替换为`type(None)`。

## 26.1.4.泛型

由于不能以通用方式静态推断容器中保存的对象的类型信息，因此已经扩展了抽象基类以支持预订来表示容器元素的预期类型。

    from typing import Mapping, Sequence

    def notify_by_email(employees: Sequence[Employee],
                        overrides: Mapping[str, str]) -> None: ...

可以通过使用在名为`TypeVar`的类型中可用的新工厂来对泛型进行参数化。

    from typing import Sequence, TypeVar

    T = TypeVar('T')      # Declare type variable

    def first(l: Sequence[T]) -> T:   # Generic function
        return l[0]

## 26.1.5.用户定义的泛型类型

用户类可以定义为通用类。

    from typing import TypeVar, Generic
    from logging import Logger

    T = TypeVar('T')

    class LoggedVar(Generic[T]):
        def __init__(self, value: T, name: str, logger: Logger) -> None:
            self.name = name
            self.logger = logger
            self.value = value

        def set(self, new: T) -> None:
            self.log('Set ' + repr(self.value))
            self.value = new

        def get(self) -> T:
            self.log('Get ' + repr(self.value))
            return self.value

        def log(self, message: str) -> None:
            self.logger.info('{}: {}'.format(self.name, message))

`Generic[T]`定义类`LoggedVar`采用单个类型参数`T` 这也使`T`有效作为类体中的类型。

`Generic`基类使用定义`__getitem__()`的元类，使得`LoggedVar[t]`有效作为类型：

    from typing import Iterable

    def zero_all_vars(vars: Iterable[LoggedVar[int]]) -> None:
        for var in vars:
            var.set(0)

泛型类型可以有任意数量的类型变量，类型变量可以被约束：

    from typing import TypeVar, Generic
    ...

    T = TypeVar('T')
    S = TypeVar('S', int, str)

    class StrangePair(Generic[T, S]):
        ...

`Generic`的每个类型变量参数必须是不同的。因此无效：

    from typing import TypeVar, Generic
    ...

    T = TypeVar('T')

    class Pair(Generic[T, T]):   # INVALID
        ...

您可以使用多个继承与`Generic`：

    from typing import TypeVar, Generic, Sized

    T = TypeVar('T')

    class LinkedList(Sized, Generic[T]):
        ...

当继承泛型类时，一些类型变量可以修复：

    from typing import TypeVar, Mapping

    T = TypeVar('T')

    class MyDict(Mapping[str, T]):
        ...

在这种情况下，`MyDict`具有单个参数`T`。

将不指定类型参数的泛型类子类化为每个位置假设`Any`。在下面的示例中，`MyIterable`不是通用的，而是隐含地继承自`Iterable[Any]`：

    from typing import Iterable

    class MyIterable(Iterable): # Same as Iterable[Any]

`Generic`使用的元类是`abc.ABCMeta` 通用类可以是通过包括抽象方法或属性的ABC，并且通用类也可以具有ABC作为基类而没有元类冲突。不支持通用元类。

## 26.1.6.`Any`类型

一种特殊类型的类型是`Any`。静态类型检查器会将每种类型视为与`Any`和`Any`兼容，与每种类型兼容。

这意味着可以对`Any`上的类型的值执行任何操作或方法调用，并将其分配给任何变量：

    from typing import Any

    a = None    # type: Any
    a = []      # OK
    a = 2       # OK

    s = ''      # type: str
    s = a       # OK

    def foo(item: Any) -> int:
        # Typechecks; 'item' could be any type,
        # and that type might have a 'bar' method
        item.bar()
        ...

请注意，在将类型`Any`的值指定为更精确的类型时，不会执行类型检查。For example, the static type checker did not report an error when assigning `a` to `s` even though `s` was declared to be of type `str` and receives an `int` value at runtime!

此外，没有返回类型或参数类型的所有函数将默认使用`Any`：

    def legacy_parser(text):
        ...
        return data

    # A static type checker will treat the above
    # as having the same signature as:
    def legacy_parser(text: Any) -> Any:
        ...
        return data

当您需要混合动态和静态类型代码时，此行为允许`Any`用作escape hatch。

对比`Any`与`object`行为的行为。与`Any`类似，每个类型都是`object`的子类型。但是，与`Any`不同，反之亦然：`object`是而不是每个其他类型的子类型。

这意味着当值的类型是`object`时，类型检查器将拒绝几乎所有的操作，并将其分配给更专门类型的变量（或使用它作为返回值）类型错误。例如：

    def hash_a(item: object) -> int:
        # Fails; an object does not have a 'magic' method.
        item.magic()
        ...

    def hash_b(item: Any) -> int:
        # Typechecks
        item.magic()
        ...

    # Typechecks, since ints and strs are subclasses of object
    hash_a(42)
    hash_a("foo")

    # Typechecks, since Any is compatible with all types
    hash_b(42)
    hash_b("foo")

使用`object`表示值可以是类型安全方式的任何类型。使用`Any`表示值是动态类型。

## 26.1.7.类，函数和装饰器

模块定义了以下类，函数和装饰器：

class `typing.``Any`

  表示无约束类型的特殊类型。

  - 任何对象都是`Any`的实例。
  - 任何类都是`Any`的子类。
  - 作为特殊情况，`Any`和`object`是彼此的子类。

class `typing.``TypeVar`

  类型变量。

  用法：

      T = TypeVar('T')  # Can be anything
      A = TypeVar('A', str, bytes)  # Must be str or bytes

  类型变量主要用于静态类型检查器的好处。它们用作泛型类型以及通用函数定义的参数。有关泛型类型的更多信息，请参阅类Generic。通用函数的工作方式如下：

      def repeat(x: T, n: int) -> Sequence[T]:
          """Return a list containing n references to x."""
          return [x]*n

      def longest(x: A, y: A) -> A:
          """Return the longest of two strings."""
          return x if len(x) >= len(y) else y

  后面的示例的声明本质上是`（str， str） - > str `（字节， 字节） - > 字节``还要注意，如果参数是`str`的某个子类的实例，则返回类型仍然是平常的`str`。

  在运行时，运行时，`isinstance（x， T）将引发`TypeError`。`一般来说，`isinstance()`和`issubclass()`不应与类型一起使用。

  类型变量可以通过传递`covariant=True`或`contravariant=True`标记为协变或逆变。有关详细信息，请参阅 PEP 484。默认类型变量是不变的。或者，类型变量可以使用`bound=<type>`来指定上界。这意味着对类型变量替换（显式或隐式）的实际类型必须是边界类型的子类型，请参见 PEP 484。

class `typing.``Union`

  共用体类型； `联合[X， Y]表示X或Y.`

  要定义共用体，请使用e。`Union [int， str]`细节：

  - 参数必须是类型，并且必须至少有一个。

  - 工会联合会是扁平的，

        Union[Union[int, str], float] == Union[int, str, float]

  - 单一参数的联合消失，e。

        Union[int] == int  # The constructor actually returns int

  - 跳过冗余参数，e。

        Union[int, str, int] == Union[int, str]

  - 当比较联合时，参数顺序被忽略，e。

        Union[int, str] == Union[str, int]

  - 如果`Any`存在，它是唯一的幸存者，

        Union[int, Any] == Any

  - 你不能子类化或实例化一个共用体。

  - 您不能写`Union[X][Y]`。

  - 您可以使用`Optional[X]`作为`联合的缩写[X， 无]`

class `typing.``Optional`

  可选类型。

  `Optional[X]`等效于`Union [X， type（None）]`

  请注意，这不是一个可选参数的概念，它是一个具有默认值的参数。具有默认值的可选参数不需要在其类型注解上使用`Optional`限定符（虽然如果默认值为`None` 如果允许显式值`None`，则强制参数可能仍然具有`Optional`类型。

class `typing.``Tuple`

  元组类型； `元组[X， Y]是两个项目的元组的类型，第一个项目类型为X，第二个项目类型为Y.`

  示例：示例：`元组[T1， T2]是对应于类型变量T1和T2的两个元素的元组。``Tuple [int， float，float， str]是一个int，int，float和string.string 。`

  要指定同构类型的变量元组，请使用字面值省略号，`Tuple [int， ...]`

class `typing.``Callable`

  可叫类型； `Callable [[int]， str]是（int） - > str.str的函数。`

  订阅语法必须始终使用两个值：参数列表和返回类型。参数列表必须是一个类型列表；返回类型必须是单个类型。

  没有用于指示可选或关键字参数的语法，这种函数类型很少用作回调类型。`Callable [...， ReturnType]可用于输入hint一个可调用的任何数量的参数并返回`ReturnType`。`平常`Callable`等效于`Callable [...， Any]`

class `typing.``Generic`

  泛型类型的抽象基类。

  通常类型通常通过从具有一个或多个类型变量的该类的实例化继承来声明。例如，通用映射类型可以定义为：

      class Mapping(Generic[KT, VT]):
          def __getitem__(self, key: KT) -> VT:
              ...
              # Etc.

  然后可以使用此类，如下所示：

      X = TypeVar('X')
      Y = TypeVar('Y')

      def lookup_name(mapping: Mapping[X, Y], key: X, default: Y) -> Y:
          try:
              return mapping[key]
          except KeyError:
              return default

class `typing.``Iterable`(Generic[T_co])

  `collections.abc.Iterable`

class `typing.``Iterator`(Iterable[T_co])

  `collections.abc.Iterator`

class `typing.``SupportsInt`

  具有一个抽象方法的ABC `__int__`。

class `typing.``SupportsFloat`

  具有一个抽象方法的ABC：`__float__`。

class `typing.``SupportsAbs`

  具有在其返回类型中是协变的一个抽象方法`__abs__`的ABC。

class `typing.``SupportsRound`

  具有一个抽象方法的ABC，它具有在其返回类型中协变的一个抽象方法`__round__`。

class `typing.``Reversible`

  具有一个抽象方法的ABC `__reversed__`返回`Iterator[T_co]`。

class `typing.``Container`(Generic[T_co])

  `collections.abc.Container`

class `typing.``AbstractSet`(Sized, Iterable[T_co], Container[T_co])

  `collections.abc.Set`

class `typing.``MutableSet`(AbstractSet[T])

  `collections.abc.MutableSet`

class `typing.``Mapping`(Sized, Iterable[KT], Container[KT], Generic[VT_co])

  `collections.abc.Mapping`

class `typing.``MutableMapping`(Mapping[KT, VT])

  `collections.abc.MutableMapping`

class `typing.``Sequence`(Sized, Iterable[T_co], Container[T_co])

  `collections.abc.Sequence`

class `typing.``MutableSequence`(Sequence[T])

  `collections.abc.MutableSequence`

class `typing.``ByteString`(Sequence[int])

  `collections.abc.ByteString`

  此类型表示类型`bytes`，`bytearray`和`memoryview`。

  作为此类型的缩写，`bytes`可用于注释上述任何类型的参数。

class `typing.``List`(list, MutableSequence[T])

  `list`的通用版本。用于注释返回类型。要注释参数，最好使用抽象容器类型，例如`Mapping`，`Sequence`或`AbstractSet`。

  这种类型可以如下使用：

      T = TypeVar('T', int, float)

      def vec2(x: T, y: T) -> List[T]:
          return [x, y]

      def keep_positives(vector: Sequence[T]) -> List[T]:
          return [item for item in vector if item > 0]

class `typing.``Set`(set, MutableSet[T])

  `builtins.set`

class `typing.``MappingView`(Sized, Iterable[T_co])

  `collections.abc.MappingView`

class `typing.``KeysView`(MappingView[KT_co], AbstractSet[KT_co])

  `collections.abc.KeysView`

class `typing.``ItemsView`(MappingView, Generic[KT_co, VT_co])

  `collections.abc.ItemsView`

class `typing.``ValuesView`(MappingView[VT_co])

  `collections.abc.ValuesView`

class `typing.``Dict`(dict, MutableMapping[KT, VT])

  `dict`的通用版本。此类型的用法如下：

      def get_position_in_index(word_list: Dict[str, int], word: str) -> int:
          return word_list[word]

class `typing.``Generator`(Iterator[T_co], Generic[T_co, T_contra, V_co])

  生成器可以通过通用类型`注释生成器[YieldType， SendType，SendType， ReturnType]`例如：

      def echo_round() -> Generator[int, float, str]:
          sent = yield 0
          while sent >= 0:
              sent = yield round(sent)
          return 'Done'

  注意，与打字模块中的许多其他泛型不同，`Generator`的`SendType`反向变化，而不是协变或不变。

  如果您的生成器只会产生值，请将`SendType`和`ReturnType`设置为`None`：

      def infinite_stream(start: int) -> Generator[int, None, None]:
          while True:
              yield start
              start += 1

  或者，将生成器注释为返回类型`Iterator[YieldType]`：

      def infinite_stream(start: int) -> Iterator[int]:
          while True:
              yield start
              start += 1

class `typing.``io`

  I / O流类型的包装器命名空间。

  This defines the generic type `IO[AnyStr]` and aliases `TextIO` and `BinaryIO` for respectively `IO[str]` and `IO[bytes]`. 这些表示由`open()`返回的I / O流的类型。

class `typing.``re`

  正则表达式匹配类型的Wrapper命名空间。

  这定义了类型别名`Pattern`和`Match`，它们对应于来自`re.compile()`和`re.match()`。These types (and the corresponding functions) are generic in `AnyStr` and can be made specific by writing `Pattern[str]`, `Pattern[bytes]`, `Match[str]`, or `Match[bytes]`.

`typing.``NamedTuple`(typename, fields)

  namedtuple的类型化版本。

  用法：

      Employee = typing.NamedTuple('Employee', [('name', str), ('id', int)])

  这相当于：

      Employee = collections.namedtuple('Employee', ['name', 'id'])

  生成的类有一个额外的属性：_field_types，给出一个dict将字段名称映射到类型。（字段名称在_fields属性中，它是namedtuple API的一部分。

`typing.``cast`(typ, val)

  将值转换为类型。

  这将返回不变的值。对于类型检查器，这表示返回值具有指定的类型，但是在运行时我们有意地不检查任何东西（我们希望这是尽可能快的）。

`typing.``get_type_hints`(obj)

  返回函数或方法对象的类型提示。

  这通常与`obj.__annotations__`相同，但它处理编码为字符串字面值的正向引用，字面值，如果必要，添加`Optional[t]`设置为None。

`@``typing.``no_type_check`(arg)

  装饰器来指示注解不是类型提示。

  参数必须是类或函数；如果它是一个类，它将递归应用于该类中定义的所有方法（但不适用于其超类或子类中定义的方法）。

  这会改变函数的位置。

`@``typing.``no_type_check_decorator`(decorator)

  装饰器给另一个装饰器`no_type_check()`效果。

  这将装饰器包装在`no_type_check()`中的装饰函数。