当前位置: 首页 > news >正文

Python 之类型注解

类型注解允许开发者显式地声明变量、函数参数和返回值的类型。但是加不加注解对于程序的运行没任何影响(是非强制的,且类型注解不影响运行时行为),属于 有了挺好,没有也行。但是大型项目按照规范添加注解的话,对于后期开发和维护是很有帮助的,毕竟不用回退好几层去推断有些变量的类型。

与原生数据类型的区别

特性类型注解原生数据类型
本质仅为代码中的类型提示信息,不影响代码运行时的行为实际存储和操作数据的结构,决定了数据的操作方式和内存占用
作用提高代码可读性,辅助静态类型检查用于实际的数据存储和处理
定义方式在变量名后使用冒号和类型名称进行标注通过赋值语句创建具体的数据对象

为什么用注解

代码补全

PyCharm 能根据类型注解提供更准确的属性/方法建议(如知道 y: str 后,输入 y. 会提示 str 的方法)。

比如我读取一个 json 文件并 json.load 后进行处理,像下面这种,在调用 data 的 items() 方法时,PyCharm 是没有方法提示的(毕竟 PyCharm 没办法未卜先知,无法提前预测加载后的 data 是什么类型,这也能理解)。

import jsonif __name__ == '__main__':data = json.load(open("data.json", encoding="utf-8"))for key1, value1 in data.items():for key2, value2 in value1.items():print(f"{key1}\t{key2}\t{value2}")

添加注解以后,代码补全提示就方便多了。 

import json
from typing import Dictif __name__ == '__main__':data: Dict[str, Dict[str, str]]  # 提前添加对 data 的注解data = json.load(open("data.json", encoding="utf-8"))for key1, value1 in data.items():for key2, value2 in value1.items():print(f"{key1}\t{key2}\t{value2}")

类型提示

添加类型注解以后,如果赋值的数据类型和注解声明的类型不一致的话,PyCharm 会进行提示,能够一眼洞察类型不符的情况,提前发现错误,避免运行时因类型错误导致的 TypeError 报错

维护方便

在多人协作或长期项目中,类型注解降低了理解代码的门槛,减少因类型混淆导致的 Bug,对于后期维护很有帮助。 

可读性提高

类型注解明确声明了参数和返回值的预期类型,使函数接口的语义一目了然。例如 def get_user(id: int) -> User 比未注解的版本更清晰,减少对参数类型的文字描述。

基础类型注解

Python 内置的基本类型可以直接用于注解。

# 变量注解
name: str = "Alice"
age: int = 30
price: float = 19.99
is_active: bool = True# 函数参数和返回值注解
def greet(name: str) -> str:return f"Hello, {name}"if __name__ == '__main__':name = "Looking"print(type(name))  # <class 'str'>greet_word = greet(name)print(greet_word)  # Hello, Looking

复合类型注解

from typing import List, Dict, Tuple, Set, Optional# 列表
numbers: List[int] = [1, 2, 3]# 字典
person: Dict[str, str] = {"name": "Alice", "email": "alice@example.com"}# 元组 (固定长度和类型)
point: Tuple[float, float] = (3.14, 2.71)# 集合
unique_numbers: Set[int] = {1, 2, 3}# 可选类型 (表示 middle_name 有值的时候是 str,无值的时候可以是 None)
middle_name: Optional[str] = None

函数类型注解

from typing import Callable# 基本函数注解
def add(a: int, b: int) -> int:return a + b# 带默认值的参数
def greet(name: str, greeting: str = "Hello") -> str:return f"{greeting}, {name}"# 函数作为参数
def apply_func(func: Callable[[int, int], int], x: int, y: int) -> int:return func(x, y)if __name__ == '__main__':v1 = add(1, 2)print(v1)  # 3v2 = greet("Looking")print(v2)  # Hello, Lookingv3 = apply_func(add, 2, 3)print(v3)  # 5

特殊类型注解

from typing import Any, Union, NoReturn, NewType# Any - 任意类型
def log(message: Any) -> None:print(message)# Union - 多个可能的类型
def square(number: Union[int, float]) -> Union[int, float]:return number ** 2# NoReturn - 函数不会正常返回
def fail() -> NoReturn:raise Exception("Something went wrong")UserId = NewType("UserId", int)
if __name__ == '__main__':log(123)  # 123log("hello world")  # hello worldprint(square(5))  # 25print(square(2.5))  # 6.25# UserId("hello")  # 类型检查不通过print(UserId(12345))  # 12345fail()# Traceback (most recent call last):#   File "E:\lky_project\tmp_project\test.py", line 24, in <module>#     fail()#   File "E:\lky_project\tmp_project\test.py", line 16, in fail#     raise Exception("Something went wrong")# Exception: Something went wrong

类型注解别名

from typing import List, Tuple# 简单别名
UserId = int# 复杂别名
Point = Tuple[float, float]
Vector = List[float]def distance(point1: Point, point2: Point) -> float:return ((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2) ** 0.5def normalize(vector: Vector) -> Vector:length = sum(x ** 2 for x in vector) ** 0.5return [x / length for x in vector]if __name__ == '__main__':point1 = (3, 4)point2 = (0, 0)print(distance(point1, point2))  # 5.0vector = [3, 4]print(normalize(vector))  # [0.6, 0.8]

泛型类型注解

from typing import TypeVar, Generic, ListT = TypeVar('T')  # 声明无约束的类型变量class Stack(Generic[T]):def __init__(self) -> None:self.items: List[T] = []def push(self, item: T) -> None:self.items.append(item)def pop(self) -> T:return self.items.pop()if __name__ == '__main__':# 使用int_stack = Stack[int]()  # 初始化实例并指定 T 的类型int_stack.push(12345)print(int_stack.items)  # [12345]str_stack = Stack[str]()str_stack.push("hello")print(str_stack.items)  # ['hello']

类型变量

from typing import TypeVar# 无约束的类型变量(表明 T 可以是无约束的任何类型)
T = TypeVar('T')# 有约束的类型变量
Number = TypeVar('Number', int, float, complex)def double(x: Number) -> Number:return x * 2def triple(x: T) -> T:return x * 3if __name__ == '__main__':print(double(123))  # 246print(triple("hello "))  # hello hello hello
http://www.xdnf.cn/news/489349.html

相关文章:

  • MCU开发学习记录16* - 看门狗学习与实践(HAL库) - IWDG与WWDG -STM32CubeMX
  • java加强 -IO流
  • 基于React的高德地图api教程005:圆形标记的绘制、删除、修改
  • 【AI学习】AI大模型技术发展研究月报的生成提示词
  • 【Linux】序列化与反序列化、会话与进程组、守护进程
  • 投影仪基础知识及选购方向小记③
  • 曝光融合(Exposure Fusion)
  • 【大模型系列篇】驱动编码助手Cursor与Windsurf工作的隐藏算法解读
  • 小结:jvm 类加载过程
  • 车道线检测----Lane-ATT
  • Linux自有服务
  • LLM学习笔记(四)信息论
  • 公路水运安全员B证主要考核内容有哪些
  • 中级统计师-统计学基础知识-第一章
  • C++ lambda表达式
  • 构建稳定的金字塔模式生态:从自然法则到系统工程
  • LVGL常见面试题
  • 腾讯云MCP数据智能处理:简化数据探索与分析的全流程指南
  • S32DS中定义的全局变量对应的路径查看${ProjDirPath}
  • ConcurrentSkipListMap的深入学习
  • 中国 MRO 的市场概况及发展趋势
  • LlamaIndex 第九篇 Indexing索引
  • C# RSA加密
  • No module named‘serial‘解决办法
  • 计算机视觉----感兴趣区域(ROI)、非极大值抑制
  • 日语简单记录
  • 物联网设备远程管理:基于代理IP的安全固件更新通道方案
  • 共有四个站进行码分多址CDMA通信。四个站的码片序列为......
  • 地磁传感器RM3100简单介绍
  • Socket echo server