创新互联Python教程:typing——类型注解支持

typing —— 类型注解支持

3.5 新版功能.

源码: Lib/typing.py

备注

python 运行时不强制执行函数和变量类型注解,但这些注解可用于类型检查器、IDE、静态检查器等第三方工具。


这个模块提供对类型提示的运行时支持。最基本的支持包括 Any , Union , Callable , TypeVar , 和 Generic 。关于完整的规范,请参考 PEP 484 。关于类型提示的简化介绍,请参考 PEP 483 。

下面的函数接收与返回的都是字符串,注解方式如下:

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

greeting 函数中,参数 name 的类型是 str,返回类型也是 str。子类型也可以当作参数。

新的功能频繁地被添加到 typing 模块中。typing_extensions 包提供了这些新功能对旧版本 Python 的向后移植。

For a summary of deprecated features and a deprecation timeline, please see Deprecation Timeline of Major Features.

参见

The documentation at https://typing.readthedocs.io/ serves as useful reference for type system features, useful typing related tools and typing best practices.

相关的 PEP

自从在 PEP 484 和 PEP 483 中首次引入类型提示以来,一些 PEP 已经修改和增强了 Python 的类型注释框架。包括:

  • PEP 526: 变量注解的语法

    引入 在函数定义之外标注变量的语法,以及 ClassVar 。

  • PEP 544: Protocol:结构子类型(静态鸭子类型)。

    引入 Protocol 和 @runtime_checkable 装饰器。

  • PEP 585: 标准集合中的类型提示泛型

    引入 types.GenericAlias 和使用标准库类作为 通用类型 的能力。

  • PEP 586: 文字类型

    引入 Literal

  • PEP 589: TypedDict: 具有固定键集的字典的类型提示

    引入 TypedDict

  • PEP 591: 为 typing 添加最终限定符

    引入 Final 和 @final 装饰器

  • PEP 593: 灵活的函数和变量注解

    引入 Annotated

  • PEP 604: 允许 X | Y 形式的联合类型写法

    引入 types.UnionType 和使用二元或运算符 | 来表示 类型联合 的能力。

  • PEP 612: 形参规格变量

    引入 ParamSpec 和 Concatenate

  • PEP 613: 显式类型别名

    引入 TypeAlias

  • PEP 646: Variadic Generics

    Introducing TypeVarTuple

  • PEP 647: 用户自定义的类型保护器

    引入 TypeGuard

  • PEP 655: Marking individual TypedDict items as required or potentially missing

    Introducing Required and NotRequired

  • PEP 673: Self type

    Introducing Self

  • PEP 675: Arbitrary Literal String Type

    Introducing LiteralString

  • PEP 681: Data Class Transforms

    Introducing the @dataclass_transform decorator

类型别名

把类型赋给别名,就可以定义类型别名。本例中,Vectorlist[float] 相同,可互换:

 
 
 
 
  1. Vector = list[float]
  2. def scale(scalar: float, vector: Vector) -> Vector:
  3. return [scalar * num for num in vector]
  4. # passes type checking; a list of floats qualifies as a Vector.
  5. new_vector = scale(2.0, [1.0, -4.2, 5.4])

类型别名适用于简化复杂的类型签名。例如:

 
 
 
 
  1. from collections.abc import Sequence
  2. ConnectionOptions = dict[str, str]
  3. Address = tuple[str, int]
  4. Server = tuple[Address, ConnectionOptions]
  5. def broadcast_message(message: str, servers: Sequence[Server]) -> None:
  6. ...
  7. # The static type checker will treat the previous type signature as
  8. # being exactly equivalent to this one.
  9. def broadcast_message(
  10. message: str,
  11. servers: Sequence[tuple[tuple[str, int], dict[str, str]]]) -> None:
  12. ...

注意,None 是一种类型提示特例,已被 type(None) 取代。

NewType

使用 NewType 助手来创建不同的类型

 
 
 
 
  1. from typing import NewType
  2. UserId = NewType('UserId', int)
  3. some_id = UserId(524313)

静态类型检查器把新类型当作原始类型的子类,这种方式适用于捕捉逻辑错误:

 
 
 
 
  1. def get_user_name(user_id: UserId) -> str:
  2. ...
  3. # passes type checking
  4. user_a = get_user_name(UserId(42351))
  5. # fails type checking; an int is not a UserId
  6. user_b = get_user_name(-1)

UserId 类型的变量可执行所有 int 操作,但返回结果都是 int 类型。这种方式允许在预期 int 时传入 UserId,还能防止意外创建无效的 UserId

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

注意,这些检查只由静态类型检查器强制执行。在运行时,语句 Derived = NewType('Derived', Base) 将产生一个 Derived 可调用对象,该对象立即返回你传递给它的任何参数。 这意味着语句 Derived(some_value) 不会创建一个新的类,也不会引入超出常规函数调用的很多开销。

更确切地说,在运行时,some_value is Derived(some_value) 表达式总为 True。

创建 Derived 的子类型是无效的:

 
 
 
 
  1. from typing import NewType
  2. UserId = NewType('UserId', int)
  3. # Fails at runtime and does not pass type checking
  4. class AdminUserId(UserId): pass

然而,我们可以在 “派生的” NewType 的基础上创建一个 NewType。

 
 
 
 
  1. from typing import NewType
  2. UserId = NewType('UserId', int)
  3. ProUserId = NewType('ProUserId', UserId)

同时,ProUserId 的类型检查也可以按预期执行。

详见 PEP 484。

备注

回顾上文,类型别名声明了两种彼此 等价 的类型。 Alias = Original 时,静态类型检查器认为 AliasOriginal 完全等价。 这种方式适用于简化复杂类型签名。

反之,NewType 声明把一种类型当作另一种类型的 子类型Derived = NewType('Derived', Original) 时,静态类型检查器把 Derived 当作 Original子类 ,即,Original 类型的值不能用在预期 Derived 类型的位置。这种方式适用于以最小运行时成本防止逻辑错误。

3.5.2 新版功能.

在 3.10 版更改: NewType 现在是一个类而不是一个函数。 在调用 NewType 而不是普通的函数时,会有一些额外的运行时间成本。 然而,这种开销将在 3.11.0 中减少。

可调对象(Callable)

预期特定签名回调函数的框架可以用 Callable[[Arg1Type, Arg2Type], ReturnType] 实现类型提示。

例如:

 
 
 
 
  1. from collections.abc import Callable
  2. def feeder(get_next_item: Callable[[], str]) -> None:
  3. # Body
  4. def async_query(on_success: Callable[[int], None],
  5. on_error: Callable[[int, Exception], None]) -> None:
  6. # Body
  7. async def on_update(value: str) -> None:
  8. # Body
  9. callback: Callable[[str], Awaitable[None]] = on_update

无需指定调用签名,用省略号字面量替换类型提示里的参数列表: Callable[..., ReturnType],就可以声明可调对象的返回类型。

以其他可调用对象为参数的可调用对象可以使用 ParamSpec 来表明其参数类型是相互依赖的。此外,如果该可调用对象增加或删除了其他可调用对象的参数,可以使用 Concatenate 操作符。 它们分别采取``Callable[ParamSpecVariable, ReturnType]`` 和 Callable[Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable], ReturnType] 的形式。

在 3.10 版更改: Callable now supports ParamSpec and Concatenate. See PEP 612 for more details.

参见

ParamSpec 和 Concatenate 的文档提供了在 Callable 中使用的例子。

泛型(Generic)

容器中,对象的类型信息不能以泛型方式静态推断,因此,抽象基类扩展支持下标,用于表示容器元素的预期类型。

 
 
 
 
  1. from collections.abc import Mapping, Sequence
  2. def notify_by_email(employees: Sequence[Employee],
  3. overrides: Mapping[str, str]) -> None: ...

typing 模块中推出的 TypeVar 工厂函数实现泛型参数化。

 
 
 
 
  1. from collections.abc import Sequence
  2. from typing import TypeVar
  3. T = TypeVar('T') # Declare type variable
  4. def first(l: Sequence[T]) -> T: # Generic function
  5. return l[0]

用户定义的泛型类型

用户定义的类可以定义为泛型类。

 
 
 
 
  1. from typing import TypeVar, Generic
  2. from logging import Logger
  3. T = TypeVar('T')
  4. class LoggedVar(Generic[T]):
  5. def __init__(self, value: T, name: str, logger: Logger) -> None:
  6. self.name = name
  7. self.logger = logger
  8. self.value = value
  9. def set(self, new: T) -> None:
  10. self.log('Set ' + repr(self.value))
  11. self.value = new
  12. def get(self) -> T:
  13. self.log('Get ' + repr(self.value))
  14. return self.value
  15. def log(self, message: str) -> None:
  16. self.logger.info('%s: %s', self.name, message)

Generic[T] 是定义类 LoggedVar 的基类,该类使用单类型参数 T。在该类体内,T 是有效的类型。

The Generic base class defines __class_getitem__() so that LoggedVar[T] is valid as a type:

 
 
 
 
  1. from collections.abc import Iterable
  2. def zero_all_vars(vars: Iterable[LoggedVar[int]]) -> None:
  3. for var in vars:
  4. var.set(0)

一个泛型可以有任何数量的类型变量。所有种类的 TypeVar 都可以作为泛型的参数:

 
 
 
 
  1. from typing import TypeVar, Generic, Sequence
  2. T = TypeVar('T', contravariant=True)
  3. B = TypeVar('B', bound=Sequence[bytes], covariant=True)
  4. S = TypeVar('S', int, str)
  5. class WeirdTrio(Generic[T, B, S]):
  6. ...

Generic 类型变量的参数应各不相同。下列代码就是无效的:

 
 
 
 
  1. from typing import TypeVar, Generic
  2. ...
  3. T = TypeVar('T')
  4. class Pair(Generic[T, T]): # INVALID
  5. ...

Generic 支持多重继承:

 
 
 
 
  1. from collections.abc import Sized
  2. from typing import TypeVar, Generic
  3. T = TypeVar('T')
  4. class LinkedList(Sized, Generic[T]):
  5. ...

继承自泛型类时,可以修正某些类型变量:

 
 
 
 
  1. from collections.abc import Mapping
  2. from typing import TypeVar
  3. T = TypeVar('T')
  4. class MyDict(Mapping[str, T]):
  5. ...

比如,本例中 MyDict 调用的单参数,T

未指定泛型类的类型参数时,每个位置的类型都预设为 Any。下例中,MyIterable 不是泛型,但却隐式继承了 Iterable[Any]

 
 
 
 
  1. from collections.abc import Iterable
  2. class MyIterable(Iterable): # Same as Iterable[Any]

还支持用户定义的泛型类型别名。例如:

 
 
 
 
  1. from collections.abc import Iterable
  2. from typing import TypeVar
  3. S = TypeVar('S')
  4. Response = Iterable[S] | int
  5. # Return type here is same as Iterable[str] | int
  6. def response(query: str) -> Response[str]:
  7. ...
  8. T = TypeVar('T', int, float, complex)
  9. Vec = Iterable[tuple[T, T]]
  10. def inproduct(v: Vec[T]) -> T: # Same as Iterable[tuple[T, T]]
  11. return sum(x*y for x, y in v)

在 3.7 版更改: Generic 不再支持自定义元类。

用户定义的参数表达式的泛型也通过 Generic[P] 形式的参数规范变量来支持。该行为与上面描述的类型变量一致,因为参数规范变量被类型化模块视为一个专门的类型变量。 这方面的一个例外是,一个类型列表可以用来替代 ParamSpec:

 
 
 
 
  1. >>> from typing import Generic, ParamSpec, TypeVar
  2. >>> T = TypeVar('T')
  3. >>> P = ParamSpec('P')
  4. >>> class Z(Generic[T, P]): ...
  5. ...
  6. >>> Z[int, [dict, float]]
  7. __main__.Z[int, (, )]

此外,一个只有一个参数规范变量的泛型将接受表格 X[[Type1, Type2, ...]] 中的参数列表,出于美观的考虑也包括 X[Type1, Type2, ...] 。 在内部,后者被转换为前者,所以下面的内容是等价的:

 
 
 
 
  1. >>> class X(Generic[P]): ...
  2. ...
  3. >>> X[int, str]
  4. __main__.X[(, )]
  5. >>> X[[int, str]]
  6. __main__.X[(, )]

请注意,带有 ParamSpec 的泛型在某些情况下可能不会有正确的``__parameters__``,因为它们主要用于静态类型检查。

在 3.10 版更改: Generic 现在可以通过参数表达式进行参数化。参见 ParamSpec 和 PEP 612 以了解更多细节。

抽象基类可作为用户定义的泛型类的基类,且不会与元类冲突。现已不再支持泛型元类。参数化泛型的输出结果会被缓存,typing 模块的大多数类型都可哈希、可进行等价对比。

Any 类型

Any 是一种特殊的类型。静态类型检查器认为所有类型均与 Any 兼容,同样,Any 也与所有类型兼容。

也就是说,可对 Any 类型的值执行任何操作或方法调用,并赋值给任意变量:

 
 
 
 
  1. from typing import Any
  2. a: Any = None
  3. a = [] # OK
  4. a = 2 # OK
  5. s: str = ''
  6. s = a # OK
  7. def foo(item: Any) -> int:
  8. # Passes type checking; 'item' could be any type,
  9. # and that type might have a 'bar' method
  10. item.bar()
  11. ...

Notice that no type checking is performed when assigning a value of type Any to a more precise type. 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:

 
 
 
 
  1. def legacy_parser(text):
  2. ...
  3. return data
  4. # A static type checker will treat the above
  5. # as having the same signature as:
  6. def legacy_parser(text: Any) -> Any:
  7. ...
  8. return data

需要混用动态与静态类型代码时,此操作把 Any 当作 应急出口

Any 和 object 的区别。与 Any 相似,所有类型都是 object 的子类型。然而,与 Any 不同,object 不可逆:object 不是 其它类型的子类型。

就是说,值的类型是 object 时,类型检查器几乎会拒绝所有对它的操作,并且,把它赋给更精确的类型变量(或返回值)属于类型错误。例如:

 
 
 
 
  1. def hash_a(item: object) -> int:
  2. # Fails type checking; an object does not have a 'magic' method.
  3. item.magic()
  4. ...
  5. def hash_b(item: Any) -> int:
  6. # Passes type checking
  7. item.magic()
  8. ...
  9. # Passes type checking, since ints and strs are subclasses of object
  10. hash_a(42)
  11. hash_a("foo")
  12. # Passes type checking, since Any is compatible with all types
  13. hash_b(42)
  14. hash_b("foo")

使用 object,说明值能以类型安全的方式转为任何类型。使用 Any,说明值是动态类型。

名义子类型 vs 结构子类型

最初 PEP 484 将 Python 静态类型系统定义为使用 名义子类型。这意味着当且仅当类 AB 的子类时,才满足有类 B 预期时使用类 A

此项要求以前也适用于抽象基类,例如,Iterable 。这种方式的问题在于,定义类时必须显式说明,既不 Pythonic,也不是动态类型式 Python 代码的惯用写法。例如,下列代码就遵从了 PEP 484 的规范:

 
 
 
 
  1. from collections.abc import Sized, Iterable, Iterator
  2. class Bucket(Sized, Iterable[int]):
  3. ...
  4. def __len__(self) -> int: ...
  5. def __iter__(self) -> Iterator[int]: ...

PEP 544 允许用户在类定义时不显式说明基类,从而解决了这一问题,静态类型检查器隐式认为 Bucket 既是 Sized 的子类型,又是 Iterable[int] 的子类型。这就是 结构子类型 (又称为静态鸭子类型):

 
 
 
 
  1. from collections.abc import Iterator, Iterable
  2. class Bucket: # Note: no base classes
  3. ...
  4. def __len__(self) -> int: ...
  5. def __iter__(self) -> Iterator[int]: ...
  6. def collect(items: Iterable[int]) -> int: ...
  7. result = collect(Bucket()) # Passes type check

此外,结构子类型的优势在于,通过继承特殊类 Protocol ,用户可以定义新的自定义协议(见下文中的例子)。

模块内容

本模块定义了下列类、函数和修饰器。

备注

本模块定义了一些类型,作为标准库中已有的类的子类,从而可以让 Generic 支持 [] 中的类型变量。Python 3.9 中,这些标准库的类已支持 [] ,因此,这些类型就变得冗余了。

Python 3.9 弃用了这些冗余类型,但解释器并未提供相应的弃用警告。标记弃用类型的工作留待支持 Python 3.9 及以上版本的类型检查器实现。

Python 3.9.0 发布五年后的首个 Python 发行版将从 typing 模块中移除这些弃用类型。详见 PEP 585 《标准集合的类型提示泛型》。

特殊类型原语

特殊类型

这些类型可用于类型注解,但不支持 []

typing.Any

不受限的特殊类型。

  • 所有类型都与 Any 兼容。

  • Any 与所有类型都兼容。

在 3.11 版更改: Any can now be used as a base class. This can be useful for avoiding type checker errors with classes that can duck type anywhere or are highly dynamic.

typing.LiteralString

Special type that includes only literal strings. A string literal is compatible with LiteralString, as is another LiteralString, but an object typed as just str is not. A string created by composing LiteralString-typed objects is also acceptable as a LiteralString.

Example:

 
 
 
 
  1. def run_query(sql: LiteralString) -> ...
  2. ...
  3. def caller(arbitrary_string: str, literal_string: LiteralString) -> None:
  4. run_query("SELECT * FROM students") # ok
  5. run_query(literal_string) # ok
  6. run_query("SELECT * FROM " + literal_string) # ok
  7. run_query(arbitrary_string) # type checker error
  8. run_query( # type checker error
  9. f"SELECT * FROM students WHERE name = {arbitrary_string}"
  10. )

This is useful for sensitive APIs where arbitrary user-generated strings could generate problems. For example, the two cases above that generate type checker errors could be vulnerable to an SQL injection attack.

See PEP 675 for more details.

3.11 新版功能.

typing.Never

The bottom type, a type that has no members.

This can be used to define a function that should never be called, or a function that never returns:

 
 
 
 
  1. from typing import Never
  2. def never_call_me(arg: Never) -> None:
  3. pass
  4. def int_or_str(arg: int | str) -> None:
  5. never_call_me(arg) # type checker error
  6. match arg:
  7. case int():
  8. print("It's an int")
  9. case str():
  10. print("It's a str")
  11. case _:
  12. never_call_me(arg) # ok, arg is of type Never

3.11 新版功能: On older Python versions, NoReturn may be used to express the same concept. Never was added to make the intended meaning more explicit.

typing.NoReturn

标记没有返回值的函数的特殊类型。例如:

 
 
 
 
  1. from typing import NoReturn
  2. def stop() -> NoReturn:
  3. raise RuntimeError('no way')

NoReturn can also be used as a bottom type, a type that has no values. Starting in Python 3.11, the Never type should be used for this concept instead. Type checkers should treat the two equivalently.

3.5.4 新版功能.

3.6.2 新版功能.

typing.Self

Special type to represent the current enclosed class. For example:

 
 
 
 
  1. from typing import Self
  2. class Foo:
  3. def return_self(self) -> Self:
  4. ...
  5. return self

This annotation is semantically equivalent to the following, albeit in a more succinct fashion:

 
 
 
 
  1. from typing import TypeVar
  2. Self = TypeVar("Self", bound="Foo")
  3. class Foo:
  4. def return_self(self: Self) -> Self:
  5. ...
  6. return self

In general if something currently follows the pattern of:

 
 
 
 
  1. class Foo:
  2. def return_self(self) -> "Foo":
  3. ...
  4. return self

You should use Self as calls to SubclassOfFoo.return_self would have Foo as the return type and not SubclassOfFoo.

Other common use cases include:

  • classmethods that are used as alternative constructors and return instances of the cls parameter.

  • Annotating an __enter__() method which returns self.

See PEP 673 for more details.

3.11 新版功能.

typing.TypeAlias

用于显式声明 类型别名 的特殊标注。 例如:

 
 
 
 
  1. from typing import TypeAlias
  2. Factors: TypeAlias = list[int]

关于显式类型别名的更多细节,请参见 PEP 613。

3.10 新版功能.

特殊形式

可用于类型注解,且支持 [] ,每种形式都有其独特的句法。

typing.Tuple

元组类型; Tuple[X, Y] 是二项元组类型,第一个元素的类型是 X,第二个元素的类型是 Y。空元组的类型可写为 Tuple[()]

例:Tuple[T1, T2] 是二项元组,类型变量分别为 T1 和 T2。Tuple[int, float, str] 是由整数、浮点数、字符串组成的三项元组。

可用省略号字面量指定同质变长元组,例如,Tuple[int, ...] 。Tuple 与 Tuple[Any, ...] 等价,也与 tuple 等价。

3.9 版后已移除: builtins.tuple now supports subscripting ([]). See PEP 585 and GenericAlias 类型.

typing.Union

联合类型; Union[X, Y] 等价于 X | Y ,意味着满足 X 或 Y 之一。

要定义一个联合类型,可以使用类似 Union[int, str] 或简写 int | str。建议使用这种简写。细节:

  • 参数必须是某种类型,且至少有一个。

  • 联合类型之联合类型会被展平,例如:

       
       
       
       
    1. Union[Union[int, str], float] == Union[int, str, float]
  • 单参数之联合类型就是该参数自身,例如:

       
       
       
       
    1. Union[int] == int # The constructor actually returns int
  • 冗余的参数会被跳过,例如:

       
       
       
       
    1. Union[int, str, int] == Union[int, str] == int | str
  • 比较联合类型,不涉及参数顺序,例如:

       
       
       
       
    1. Union[int, str] == Union[str, int]
  • Union 不能作为子类,也不能实例化。

  • 不支持 Union[X][Y] 这种写法。

在 3.7 版更改: 在运行时,不要移除联合类型中的显式子类。

在 3.10 版更改: 联合类型现在可以写成 X | Y。 参见 联合类型表达式。

typing.Optional

可选类型。

Optional[X] 等价于 X | None (或 Union[X, None] ) 。

注意,可选类型与含默认值的可选参数不同。含默认值的可选参数不需要在类型注解上添加 Optional 限定符,因为它仅是可选的。例如:

 
 
 
 
  1. def foo(arg: int = 0) -> None:
  2. ...

另一方面,显式应用 None 值时,不管该参数是否可选, Optional 都适用。例如:

 
 
 
 
  1. def foo(arg: Optional[int] = None) -> None:
  2. ...

在 3.10 版更改: 可选参数现在可以写成 X | None。 参见 联合类型表达式。

typing.Callable

可调类型; Callable[[int], str] 是把(int)转为 str 的函数。

下标句法必须与参数列表和返回类型这两个值一起使用。参数列表只能是类型列表或省略号;返回类型只能是单一类型。

没有说明可选参数或关键字参数的句法;这类函数类型很少用作回调类型。Callable[..., ReturnType] (省略号字面量)可用于为接受任意数量参数,并返回 ReturnType 的可调对象提供类型提示。纯 Callable 等价于 Callable[..., Any],进而等价于 collections.abc.Callable 。

以其他可调用对象为参数的可调用对象可以使用 ParamSpec 来表明其参数类型是相互依赖的。此外,如果该可调用对象增加或删除了其他可调用对象的参数,可以使用 Concatenate 操作符。 它们分别采取``Callable[ParamSpecVariable, ReturnType]`` 和 Callable[Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable], ReturnType] 的形式。

3.9 版后已移除: collections.abc.Callable now supports subscripting ([]). See PEP 585 and GenericAlias 类型.

在 3.10 版更改: Callable now supports ParamSpec and Concatenate. See PEP 612 for more details.

参见

ParamSpec 和 Concatenate 的文档提供了使用 Callable 的例子。

typing.Concatenate

Used with Callable and ParamSpec to type annotate a higher order callable which adds, removes, or transforms parameters of another callable. Usage is in the form Concatenate[Arg1Type, Arg2Type, ..., ParamSpecVariable]. Concatenate is currently only valid when used as the first argument to a Callable. The last parameter to Concatenate must be a ParamSpec or ellipsis (...).

例如,为了注释一个装饰器 with_lock,它为被装饰的函数提供了 threading.Lock,Concatenate 可以用来表示 with_lock 期望一个可调用对象,该对象接收一个 Lock 作为第一个参数,并返回一个具有不同类型签名的可调用对象。 在这种情况下,ParamSpec 表示返回的可调用对象的参数类型取决于被传入的可调用程序的参数类型:

 
 
 
 
  1. from collections.abc import Callable
  2. from threading import Lock
  3. from typing import Concatenate, ParamSpec, TypeVar
  4. P = ParamSpec('P')
  5. R = TypeVar('R')
  6. # Use this lock to ensure that only one thread is executing a function
  7. # at any time.
  8. my_lock = Lock()
  9. def with_lock(f: Callable[Concatenate[Lock, P], R]) -> Callable[P, R]:
  10. '''A type-safe decorator which provides a lock.'''
  11. def inner(*args: P.args, **kwargs: P.kwargs) -> R:
  12. # Provide the lock as the first argument.
  13. return f(my_lock, *args, **kwargs)
  14. return inner
  15. @with_lock
  16. def sum_threadsafe(lock: Lock, numbers: list[float]) -> float:
  17. '''Add a list of numbers together in a thread-safe manner.'''
  18. with lock:
  19. return sum(numbers)
  20. # We don't need to pass in the lock ourselves thanks to the decorator.
  21. sum_threadsafe([1.1, 2.2, 3.3])

3.10 新版功能.

参见

  • PEP 612 — 参数规范变量(引入 ParamSpecConcatenate 的 PEP)。

  • ParamSpec 和 Callable。

class typing.Type(Generic[CT_co])

C 注解的变量可以接受类型 C 的值。反之,用 Type[C] 注解的变量可以接受类自身的值 — 准确地说,是接受 C类对象,例如:

 
 
 
 
  1. a = 3 # Has type 'int'
  2. b = int # Has type 'Type[int]'
  3. c = type(a) # Also has type 'Type[int]'

注意,Type[C] 为协变量:

 
 
 
 
  1. class User: ...
  2. class BasicUser(User): ...
  3. class ProUser(User): ...
  4. class TeamUser(User): ...
  5. # Accepts User, BasicUser, ProUser, TeamUser, ...
  6. def make_new_user(user_class: Type[User]) -> User:
  7. # ...
  8. return user_class 网页题目:创新互联Python教程:typing——类型注解支持
    本文路径:http://www.shufengxianlan.com/qtweb/news17/376567.html

    网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

    广告

    声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联