Python3 类型注解
Python 类型注解(Type Hints)是自 Python 3.5 引入的一种特性,它允许开发者在定义函数、变量时指定数据类型。类型注解并非强制执行的,它们主要用于提高代码的可读性和可维护性,并支持静态分析工具进行类型检查。类型注解不会影响 Python 的动态特性,也不会在运行时被强制执行,尤其是在大型项目中可以帮助开发者减少错误。
Python 类型注解文档:https://docs.python.org/zh-cn/3.13/library/typing.html
1. 基本语法
类型注解的基本语法包括在变量声明或函数定义中使用冒号 : 来指定参数的类型,并且使用箭头 -> 来指明函数的返回值类型。
变量注解:
# 内置类型注解 int, float, bool, str
age: int = 20
# Python 3.9+
items: list[int] = [1, 2, 3]
# Python 3.8及以下版本
from typing import List, Dict, Tuple, Set
# 列表中元素为整数
numbers: List[int] = [1, 2, 3]
# 字典键为字符串,值为浮点数
prices: Dict[str, float] = {"apple": 2.5, "banana": 1.2}
# 元组内有两个元素,分别是字符串和整数
pair: Tuple[str, int] = ("hello", 42)
# 集合中元素为布尔值
flags: Set[bool] = {True, False}
对于内置类型如 int, float, bool, str 等,可以直接使用这些类型作为注解。此外,Python 还提供了对容器类型的支持,比如列表 list、元组 tuple、字典 dict 和集合 set。在 Python 3.9 及以上版本中,可以直接使用标准库中的容器类型进行类型注解;而在更早的版本中,则需要从 typing 模块导入相应的泛型容器类型。
函数注解:
def greet(name: str) -> str:
return 'Hello, ' + name
这里 name: str
表示期望传入的 name
参数是一个字符串,而 -> str
表示这个函数应该返回一个字符串。
2.复杂类型注解
除了简单的内置类型外,typing
模块还提供了更多复杂的类型构造器来创建复合类型。
1. Union 类型
Union 用来表示一个变量或函数参数可以接受多种类型中的任意一种。例如,如果一个函数既可以接收整数也可以接收字符串作为参数,我们可以这样写:
from typing import Union
def normalize_id(id: Union[int, str]) -> str:
return str(id)
# 在这个例子中,`normalize_id` 函数的参数 `id` 可以是 `int` 或者 `str` 类型。
2. Optional 类型
Optional即表示一个变量可以是给定类型的值或者是 None
。这对于可能为空的返回值或参数非常有用:
from typing import Optional
def get_first_element(lst: list) -> Optional[str]:
if lst:
return lst[0]
else:
return None
# get_first_element 函数的返回值可能是列表的第一个元素(假设是字符串)或者当列表为空时返回 `None`。
3. Callable 类型
Callable 用来描述一个可调用对象(如函数、方法或类),它指定了该对象接收的参数类型以及返回值类型。这有助于确保传递给其他函数的回调函数具有正确的签名:
from typing import Callable
def invoke_callback(callback: Callable[[int], str], value: int) -> str:
return callback(value)
# 定义符合上述签名的回调函数
def stringifier(number: int) -> str:
return f"Number is {number}"
# 调用 invoke_callback 并传入回调函数
result = invoke_callback(stringifier, 42)
# Callable[[Arg1Type, Arg2Type], ReturnType]
# Callable[[参数1类型,参数2类型], 返回值类型]
4. Literal 类型
Literal 用来限制变量只能取某些特定的字面量值。这对于配置选项、枚举值等场景特别有用,因为可以确保只允许预先定义好的几个值:
from typing import Literal
def set_mode(mode: Literal['read', 'write']) -> None:
print(f"Mode set to {mode}")
set_mode('read') # 正确
set_mode('execute') # 错误,在静态分析时会被捕获
5. TypeAlias 类型
TypeAlias 允许为复杂类型创建别名,使得代码更加简洁且易于理解。从 Python 3.11 开始,TypeAlias
成为了正式的一部分,但在此之前可以通过简单的赋值来创建类型别名:
from typing import TypeAlias, List
# Python 3.11前直接赋值创建类型别名
vector = List[float]
# Python 3.11 后使用TypeAlias创建类型别名
Vector: TypeAlias = List[float]
def scale_vector(v: Vector, factor: float) -> Vector:
return [x * factor for x in v]
vector_example: Vector = [1.0, 2.0, 3.0]
scaled_vector = scale_vector(vector_example, 2.0)
6. Any 类型
当不确定或者不关心具体的类型时,可以使用 Any
类型:
from typing import Any
def log(message: Any) -> None:
print(message)
3. 协变与逆变
在 Python 的类型系统中,协变(Covariant)和逆变(Contravariant)用于描述类型之间的关系,特别是在容器类型中。
- 协变:如果
Cat
是Animal
的子类,那么List[Cat]
也可以被视为List[Animal]
的子类。这种情况下,我们说List
对其元素类型是协变的。 - 逆变:对于某些类型的容器,如函数参数,如果我们有一个接受
Animal
类型参数的函数,那么它也能够接受接受Cat
类型参数的函数作为参数。这里,函数参数位置上的类型是逆变的。
Python 的 typing
模块中,Sequence
和 Mapping
等类型默认是协变的,而 Callable
默认是逆变于输入参数且协变于返回值。
4.泛型类
TypeVar 用于创建类型变量,这些变量可以被用作泛型类型的参数。类型变量允许你在定义函数、类或方法时指定某些参数或返回值的类型可以是任意类型,但是调用者必须提供一个具体的类型来替代这个类型变量。TypeVar 主要用于定义泛型函数、类和容器。
from typing import TypeVar, List
T = TypeVar('T') # 创建一个名为 T 的类型变量
def first_element(lst: List[T]) -> T:
"""Return the first element of a non-empty list."""
return lst[0] if lst else None
在这个例子中,T 是一个类型变量,它表示 first_element 函数可以接受任何类型的列表,并且返回该列表中元素的相同类型。这意味着如果你传入一个 List[int],那么返回值也将是 int 类型;如果你传入 List[str],则返回值将是 str 类型。
5. NewType
NewType
是 Python 的 typing
模块提供的一个工具,用于创建名义上不同的类型。尽管这些新类型的值实际上与原始类型具有相同的底层表示,但在静态类型检查时,它们被视为完全不同的类型。这有助于提高代码的安全性和可读性,因为它可以防止在不应该的地方互换使用看似相似的类型。NewType
接受两个参数:第一个是新类型的名称,第二个是现有类型的引用。下面是一个简单的例子:
from typing import NewType
UserId = NewType('UserId', int)
def get_user_name(user_id: UserId) -> str:
# 在这里实现获取用户名的逻辑
return f"User {user_id}"
# 正确使用
user_id = UserId(42)
print(get_user_name(user_id))
# 错误使用(静态分析会捕捉到这个错误)
# print(get_user_name(42)) # 类型检查器将报告错误
在这个例子中,UserId
被定义为 int
的一种特殊形式。然而,在静态类型检查期间,UserId
和 int
将被视为不同的类型。因此,直接传递一个整数给 get_user_name
函数会导致类型检查错误,而传递一个 UserId
对象则是正确的。
6. 静态类型检查设置
对于 VSCode,通常只需要确保安装了 Python 扩展,并且启用了类型检查功能。可以在设置中搜索 Python › Analysis: Type Checking Mode
并选择 basic
或 strict
模式。测试代码:
from typing import NewType
UserId = NewType('UserId', int)
def get_user_name(user_id: UserId) -> str:
return f"User {user_id}"
# 正确使用
user_id = UserId(42)
print(get_user_name(user_id))
# 错误使用
print(get_user_name(42)) # 类型检查器应报告错误
标签:13,int,Python,user,str,typing,类型,注解,Python3
From: https://www.cnblogs.com/littlecamel/p/18673603