当前位置: 首页 > 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

相关文章:

  • Java项目使用Tomcat启动后JS文件中的中文乱码问题
  • 彻底删除Docker容器中的环境变量
  • 【Win32 API】 lstrcmpA()
  • 第J1周:ResNet-50算法实战与解析
  • entity线段材质设置
  • let、var、const的区别
  • 基于javaweb的SSM驾校管理系统设计与实现(源码+文档+部署讲解)
  • 软考第六章知识点总结
  • 如何安装cuda版本的pytorch
  • PTN中的L2VPN与L3VPN技术详解
  • 时频分析的应用—外部信号的显影和定点清除
  • LLM笔记(七)注意力机制
  • WL-G4048 Multi-Port PCIe 4.0 Switch
  • 学习状态不佳时的有效利用策略
  • 团队模式总结
  • 【信息系统项目管理师】第6章:项目管理概论 - 31个经典题目及详解
  • 前端开发笔记与实践
  • 小黑独自享受思考心流:80. 删除有序数组中的重复项 II
  • 项目管理进阶:全文解读企业IT系统全生命周期管理与运营平台建设方案【附全文阅读】
  • 广州附医华南医院MDT团队新技术赋能「睡眠障碍治疗」:告别单一、反复、不对症,实现精准快速起效!
  • AI赋能科学红毯,机器人与科学家在虚实之间叩问“科学精神”
  • 朱雀二号改进型遥二运载火箭发射成功
  • 竞彩湃|欧联杯决赛前,曼联、热刺继续划水?
  • 贝壳一季度收入增长42%:二手房市场活跃度维持在高位
  • 泰山、华海、中路等山东险企综合成本率均超100%,承保业务均亏损
  • 金砖国家召开经贸联络组司局级特别会议,呼吁共同抵制单边主义和贸易保护主义