# Python类型标注有什么用?常见类型应该怎么写?
面试官问:"Python类型标注有什么用?常见类型应该怎么写?"
很多人会答"类型标注就是给变量加类型",但这只是表面现象。真正要讲清楚的是:类型标注是可选的静态类型提示,不影响运行时行为,主要用于IDE提示、静态检查工具和文档生成,帮助提前发现类型错误和提高代码可读性。
# 简要回答
类型标注(Type Hints) 是Python 3.5+引入的语法,用于标注变量、函数参数和返回值的类型。
核心特点:
- 可选的:不写类型标注不影响程序运行。
- 不强制:运行时不检查类型,标注错误也能执行。
- 给工具用的:IDE、mypy等工具读取标注提供提示和检查。
基础类型标注语法:
# 变量标注
age: int = 25
name: str = "Python"
# 函数标注
def add(a: int, b: int) -> int:
return a + b
# 容器类型
from typing import List, Dict, Tuple
names: List[str] = ["Python", "Java"]
scores: Dict[str, int] = {"Python": 95}
point: Tuple[int, int] = (10, 20)
2
3
4
5
6
7
8
9
10
11
12
13
14
主要作用:
- IDE自动补全和类型提示更准确。
- 静态检查工具(mypy)提前发现类型错误。
- 代码可读性更好,函数接口更清晰。
- 生成更好的文档。
# 详细回答
# 基础类型标注
内置类型可以直接使用:
# 基础类型
count: int = 10
price: float = 99.5
name: str = "Python"
is_valid: bool = True
# 函数参数和返回值
def greet(name: str) -> str:
return f"Hello, {name}"
# 无返回值
def log(message: str) -> None:
print(message)
2
3
4
5
6
7
8
9
10
11
12
13
# 容器类型标注
Python 3.9+可以直接使用内置容器类型:
# Python 3.9+
names: list[str] = ["Python", "Java"]
scores: dict[str, int] = {"Python": 95}
point: tuple[int, int] = (10, 20)
unique: set[int] = {1, 2, 3}
2
3
4
5
Python 3.5-3.8需要从typing模块导入:
from typing import List, Dict, Tuple, Set
names: List[str] = ["Python", "Java"]
scores: Dict[str, int] = {"Python": 95}
point: Tuple[int, int] = (10, 20)
unique: Set[int] = {1, 2, 3}
2
3
4
5
6
# Optional和Union
Optional[X]表示值可以是X或None:
from typing import Optional
def find_user(user_id: int) -> Optional[str]:
if user_id > 0:
return "User"
return None
# Optional[str] 等价于 Union[str, None]
2
3
4
5
6
7
8
Union表示多种可能类型:
from typing import Union
def process(value: Union[int, str]) -> str:
return str(value)
# Python 3.10+ 可以用 | 运算符
def process(value: int | str) -> str:
return str(value)
2
3
4
5
6
7
8
# Any和泛型
Any表示任意类型:
from typing import Any
def log(message: Any) -> None:
print(message)
2
3
4
泛型函数:
from typing import TypeVar, List
T = TypeVar('T')
def first(items: List[T]) -> T:
return items[0]
# T会根据实际参数推断类型
num = first([1, 2, 3]) # T 推断为 int
name = first(["a", "b"]) # T 推断为 str
2
3
4
5
6
7
8
9
10
# Callable标注
函数作为参数的标注:
from typing import Callable
def apply(func: Callable[[int, int], int], a: int, b: int) -> int:
return func(a, b)
def add(x: int, y: int) -> int:
return x + y
result = apply(add, 3, 5)
2
3
4
5
6
7
8
9
Callable[[参数类型列表], 返回类型]
# 类和自定义类型
类本身就是类型:
class User:
def __init__(self, name: str):
self.name: str = name
def greet(user: User) -> str:
return f"Hello, {user.name}"
2
3
4
5
6
前向引用(类在定义前使用):
from __future__ import annotations
class Node:
def __init__(self, value: int, next: Node | None = None):
self.value = value
self.next = next
2
3
4
5
6
或使用字符串:
class Node:
def __init__(self, value: int, next: "Node | None" = None):
self.value = value
self.next = next
2
3
4

# 使用mypy检查类型
mypy是最常用的Python静态类型检查工具:
pip install mypy
mypy your_script.py
2
示例代码:
def add(a: int, b: int) -> int:
return a + b
result: str = add(1, 2) # 类型错误
2
3
4
mypy输出:
error: Incompatible types in assignment (expression has type "int", variable has type "str")
运行时不报错,但mypy会提前发现问题。
# 类型标注不强制检查
即使标注错误,代码也能运行:
def add(a: int, b: int) -> int:
return a + b
# 传入字符串,标注说是int
result = add("hello", "world")
print(result) # helloworld,正常运行
2
3
4
5
6
Python运行时不检查类型标注。标注只是提示,不是约束。
# 运行时访问标注
标注存储在__annotations__属性中:
def add(a: int, b: int) -> int:
return a + b
print(add.__annotations__)
# {'a': <class 'int'>, 'b': <class 'int'>, 'return': <class 'int'>}
2
3
4
5
可以用于运行时类型检查或序列化框架(如Pydantic)。
# 知识拓展
Q1: 类型标注会影响性能吗?
几乎不影响。标注在解析时被读取并存储,但不参与运行时类型检查。唯一开销是存储标注的内存和解析标注表达式的时间,对正常程序可以忽略。
Q2: 什么时候应该写类型标注?
推荐场景:
- 公共API和库代码,接口需要清晰。
- 复杂项目,团队协作需要类型约束。
- 容易混淆的函数,标注提高可读性。
- 使用mypy等工具做静态检查。
不必要场景:
- 一次性脚本。
- 类型显而易见的简单函数。
- 频繁变化的原型代码。
Q3: 如何标注可变长参数?
def log(*args: str, **kwargs: int) -> None:
pass
# args的类型是tuple[str, ...]
# kwargs的类型是dict[str, int]
2
3
4
5
标注的是单个元素的类型,不是整个元组或字典。
Q4: 类型标注和鸭子类型矛盾吗?
不矛盾。类型标注是可选的,不写标注仍然是鸭子类型。写了标注只是给工具提供检查依据,不改变Python的动态特性。可以用Protocol标注鸭子类型:
from typing import Protocol
class Drawable(Protocol):
def draw(self) -> None: ...
def render(obj: Drawable) -> None:
obj.draw()
2
3
4
5
6
7
任何有draw()方法的对象都满足Drawable,不需要显式继承。
Q5: Python 3.10+的新语法有哪些?
- 联合类型:
int | str代替Union[int, str] - 类型别名:
type Point = tuple[int, int] - 泛型语法:
def first[T](items: list[T]) -> T: ...
这些语法更简洁,但要求Python 3.10+。
评论
验证登录状态...