类型注解概述
类型注解是在代码中为变量、函数参数和返回值标明期望的数据类型,提高代码可读性并借助工具进行静态检查
Python 是一门动态类型语言:变量可以在运行时改变类型,不需要提前声明。这在带来灵活性的同时,也带来了隐患——类型错误只能等到程序运行时才能被发现。
类型注解的出现解决了这个问题:
1 2 3 4 5 6 7 def double (x ): return x * 2 def double (x: int ) -> int : return x * 2
类型注解的好处:
提高可读性 — 一看就知道变量/函数期望什么类型
编辑器智能提示 — IDE 能根据类型提供自动补全和错误提示
静态类型检查 — 使用 mypy 等工具在运行前发现类型错误
更好的文档 — 类型信息本身就是一种精确的代码文档
注意:Python 的类型注解在运行时不会强制检查——它只是一种"标注",不会影响程序的执行。
变量的类型注解
在变量名后使用 : 类型 的语法标注变量的期望类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 """ 变量类型注解语法: 变量名: 类型 = 值 """ name: str = "PyTs1n9" age: int = 25 height: float = 1.75 is_student: bool = True title: str print (__annotations__)
1 2 3 4 x: int = "hello" print (type (x))
函数的类型注解
为函数的参数和返回值添加类型注解,是类型注解最常用也最有价值的场景
参数与返回值注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 """ 函数类型注解语法: def 函数名(参数: 类型, ...) -> 返回类型: pass """ def greet (name: str , times: int ) -> str : """重复问好""" return f"你好 {name} !" * times result = greet("PyTs1n9" , 3 ) print (result) def log_message (msg: str ) -> None : """只打印,不返回""" print (f"[LOG] {msg} " )
1 2 3 4 5 6 7 def create_user (name: str , age: int = 18 , active: bool = True ) -> dict : return {"name" : name, "age" : age, "active" : active} print (create_user("小明" ))
获取函数注解信息
1 2 3 4 5 6 7 8 def add (a: int , b: int ) -> int : return a + b print (add.__annotations__)
复合类型注解
使用 typing 模块中的工具来注解列表、字典、元组等复合容器类型
列表、字典、元组、集合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 from typing import List , Dict , Tuple , Set def get_scores (students: List [str ] ) -> List [int ]: """返回学生对应的分数列表""" return [len (name) * 10 for name in students] scores: List [int ] = [85 , 92 , 78 , 90 ] def build_info (name: str , age: int ) -> Dict [str , int ]: return {name: age} config: Dict [str , str ] = {"host" : "localhost" , "port" : "8080" } def get_position () -> Tuple [float , float ]: """返回坐标 (x, y)""" return (3.14 , 2.72 ) ids: Set [int ] = {1 , 2 , 3 , 4 }
Python 3.9+ 的新语法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 """ Python 3.9 之后,可以直接使用内置的 list、dict、tuple、set 来注解 不需要从 typing 导入 List、Dict 等(这些已被弃用) """ def get_scores (students: list [str ] ) -> list [int ]: return [len (name) * 10 for name in students] def build_info (name: str , age: int ) -> dict [str , int ]: return {name: age} config: dict [str , str ] = {"host" : "localhost" }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from typing import List , Dict matrix: List [List [int ]] = [ [1 , 2 , 3 ], [4 , 5 , 6 ], [7 , 8 , 9 ] ] classes: Dict [str , List [str ]] = { "一班" : ["小明" , "小红" , "小刚" ], "二班" : ["小王" , "小李" , "小张" ] } grades: Dict [str , Dict [str , int ]] = { "小明" : {"语文" : 85 , "数学" : 92 }, "小红" : {"语文" : 90 , "数学" : 88 } }
Union 与 Optional
Union 表示多种类型中的一种,Optional 是 Union[X, None] 的简写
Union 类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 """ Union[类型1, 类型2, ...] 表示参数可以是多种类型中的一种 适用场景:一个参数可以接受不同类型的值 """ from typing import Union def show_age (age: Union [int , str ] ) -> str : """显示年龄""" return f"年龄:{age} 岁" print (show_age(18 )) print (show_age("十八" )) def process (data: Union [int , float , str ] ) -> str : """处理不同类型的数据""" if isinstance (data, str ): return f"字符串:{data} " return f"数字:{data} "
Optional 类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 """ Optional[类型] 等价于 Union[类型, None] 表示参数可以是某种类型,也可以是 None """ from typing import Optional def greet (name: str , nickname: Optional [str ] = None ) -> str : if nickname: return f"{name} ({nickname} ),你好!" return f"{name} ,你好!" print (greet("张三" )) print (greet("张三" , nickname="三哥" )) def greet2 (name: str , nickname: Union [str , None ] = None ) -> str : pass
1 2 3 4 5 6 7 8 def find_user (user_id: int ) -> Optional [dict ]: """查找用户,找不到返回 None""" users = {1 : {"name" : "小明" }, 2 : {"name" : "小红" }} return users.get(user_id) result = find_user(3 ) print (result)
特殊类型注解
typing 模块提供了 Any、Callable、Literal 等特殊类型,处理更复杂的类型场景
Any — 任意类型
1 2 3 4 5 6 7 8 9 10 11 12 13 """ Any 表示任意类型,相当于"不进行类型检查" 适合确实无法确定类型或逐步引入注解的场景 """ from typing import Any def debug_print (value: Any ) -> None : print (f"[DEBUG] {type (value).__name__} : {value} " ) debug_print(42 ) debug_print("hello" ) debug_print([1 , 2 , 3 ])
Callable — 可调用对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 """ Callable[[参数类型, ...], 返回类型] 表示一个可调用对象(函数) """ from typing import Callable def register_callback (callback: Callable [[str ], None ] ) -> None : """注册回调函数""" callback("数据加载完成" ) def on_complete (msg: str ) -> None : print (f"收到通知:{msg} " ) register_callback(on_complete)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from typing import Callable def apply_twice (func: Callable [[int ], int ], value: int ) -> int : """将函数应用两次""" return func(func(value)) def add_three (x: int ) -> int : return x + 3 print (apply_twice(add_three, 10 ))
Literal — 字面量类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 """ Literal 限制变量只能取指定的几个值 适合表示状态、模式等有限选项 """ from typing import Literal def set_mode (mode: Literal ["read" , "write" , "append" ] ) -> str : return f"当前模式:{mode} " print (set_mode("read" )) def move (direction: Literal ["上" , "下" , "左" , "右" ], step: int ) -> None : print (f"向{direction} 移动了{step} 步" )
类型别名与自定义类型
通过类型别名给复杂的类型注解起一个简短的名字,提高可读性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 """ 类型别名:将复杂的类型组合赋值给一个有意义的名称 """ def process_scores (scores: dict [str , list [int ]] ) -> dict [str , float ]: pass StudentScores = dict [str , list [int ]] Averages = dict [str , float ] def process_scores (scores: StudentScores ) -> Averages: """计算每个学生的平均分""" return {name: sum (sc) / len (sc) for name, sc in scores.items()} scores: StudentScores = { "小明" : [85 , 92 , 78 ], "小红" : [90 , 88 , 95 ] } print (process_scores(scores))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from typing import Union , List , Dict Point = tuple [float , float ] StudentInfo = dict [str , Union [str , int , list [int ]]] Callback = callable [[str ], None ] Matrix = list [list [int ]] def distance (p1: Point, p2: Point ) -> float : """计算两点间的距离""" import math return math.sqrt((p2[0 ] - p1[0 ]) ** 2 + (p2[1 ] - p1[1 ]) ** 2 )
类型检查工具
类型注解本身不强制检查,需要借助 mypy 等静态类型检查工具来发挥作用
mypy 的使用
1 2 3 4 5 6 7 8 """ mypy 是 Python 最常用的静态类型检查工具 安装和基本使用(终端中): """
1 2 3 4 5 6 7 8 9 10 11 """ 文件 test_types.py: """ def add (a: int , b: int ) -> int : return a + b result = add("hello" , 5 )
IDE 集成的好处
1 2 3 4 5 6 7 8 9 10 11 12 """ 即使不运行 mypy,类型注解也能提升开发体验: """ def shout (name: str ) -> str : return name.upper() + "!!!"
综合练习
将类型注解知识融会贯通,在实际场景中体验带类型注解的代码带来的清晰度提升
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 """ 练习一:学生成绩管理系统(带完整类型注解) """ from typing import Optional StudentRecord = dict [str , object ] ScoreList = list [dict [str , int ]] class GradeManager : """成绩管理器""" def __init__ (self, class_name: str ) -> None : self .class_name: str = class_name self .students: list [StudentRecord] = [] def add_student ( self, name: str , age: int , scores: dict [str , int ] ) -> None : """添加学生""" total = sum (scores.values()) avg = total / len (scores) if scores else 0 self .students.append({ "name" : name, "age" : age, "scores" : scores, "total" : total, "avg" : avg }) print (f"学生 {name} 已添加(平均分:{avg:.1 f} )" ) def find_student (self, name: str ) -> Optional [StudentRecord]: """查找学生,找不到返回 None""" for stu in self .students: if stu["name" ] == name: return stu return None def get_top_students (self, top_n: int = 3 ) -> list [StudentRecord]: """获取平均分最高的 N 名学生""" sorted_students = sorted ( self .students, key=lambda s: s["avg" ], reverse=True ) return sorted_students[:top_n] def show_report (self ) -> None : """打印班级报表""" print (f"\n===== {self.class_name} 成绩报表 =====" ) for i, stu in enumerate (self .get_top_students(len (self .students)), 1 ): print ( f"{i} . {stu['name' ]} — " f"总分:{stu['total' ]} ,平均:{stu['avg' ]:.1 f} " )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 """ 练习二:带类型注解的工具函数库 """ from typing import Callable def safe_divide (a: float , b: float , default: float = 0.0 ) -> float : """安全除法,除数为零时返回默认值""" return a / b if b != 0 else default def filter_list ( items: list [int ], condition: Callable [[int ], bool ] ) -> list [int ]: """按条件过滤列表""" return [item for item in items if condition(item)] def group_by_key ( items: list [dict [str , object ]], key: str ) -> dict [str , list [dict [str , object ]]]: """按指定键对字典列表进行分组""" result: dict [str , list [dict [str , object ]]] = {} for item in items: k = str (item.get(key, "" )) if k not in result: result[k] = [] result[k].append(item) return result print (safe_divide(10 , 2 )) print (safe_divide(10 , 0 )) nums = [1 , 2 , 3 , 4 , 5 , 6 ] even = filter_list(nums, lambda x: x % 2 == 0 ) print (even)
类型注解是 Python 从"动态灵活"走向"工程可靠"的桥梁。从变量到函数、从简单类型到 Union 和 Optional、从内置容器到类型别名,每个注解都在让代码更加清晰可维护。结合 mypy 和 IDE 的类型检查能力,你能在编码阶段就发现大量潜在的类型错误——而不必等到程序崩溃时再排查。记住:Python 不会在运行时强制执行注解,它是对人(以及 IDE 和检查工具)的承诺,而不是对解释器的指令。
Python Study Note 系列文章
Python Study Note Python 函数使用(四) Python 判断语句(二) Python 基础语法(一) Python 异常处理(七) Python 循环语句(三) Python 数据容器(五) Python 文件基础操作(六) Python 模块与包(八) Python 类型注解(十) Python 面向对象(九)重点 Python 高阶技巧(十一)