类型注解与提示
类型注解基础
Python 3.5引入了类型注解(Type Hints),允许你在代码中指定变量和函数的类型。这有助于代码可读性和IDE支持。
# 基本类型注解
name: str = "Alice"
age: int = 25
height: float = 1.68
is_student: bool = True
# 函数类型注解
def greet(name: str) -> str:
return f"Hello, {name}!"
# 多个参数
def calculate(x: int, y: int) -> int:
return x + y
typing模块
Python的typing模块提供了更丰富的类型支持。
from typing import List, Dict, Tuple, Set, Optional, Union
# 列表类型
numbers: List[int] = [1, 2, 3, 4, 5]
names: List[str] = ["Alice", "Bob", "Charlie"]
# 字典类型
scores: Dict[str, int] = {"Alice": 90, "Bob": 85}
# 元组类型
point: Tuple[int, int] = (10, 20)
# 集合类型
unique_numbers: Set[int] = {1, 2, 3, 4, 5}
# 可选类型(值可以是None)
def greet_optional(name: Optional[str] = None) -> str:
if name is None:
return "Hello, Stranger!"
return f"Hello, {name}!"
# 联合类型
def process_value(value: Union[int, str]) -> str:
if isinstance(value, int):
return f"Processing integer: {value}"
return f"Processing string: {value}"
TypeVar和泛型
TypeVar允许创建可重用的类型注解。
from typing import TypeVar, List, Dict
T = TypeVar('T') # 定义类型变量
def first_element(lst: List[T]) -> T:
return lst[0]
# 使用
numbers: List[int] = [1, 2, 3]
result: int = first_element(numbers)
names: List[str] = ["Alice", "Bob"]
result: str = first_element(names)
# 多个类型变量
K = TypeVar('K')
V = TypeVar('V')
def get_first_key(d: Dict[K, V]) -> K:
return next(iter(d))
scores: Dict[str, int] = {"Alice": 90, "Bob": 85}
name: str = get_first_key(scores)
Callable类型
from typing import Callable, List
# 函数类型
def apply(func: Callable[[int, int], int], x: int, y: int) -> int:
return func(x, y)
# 使用lambda
result = apply(lambda a, b: a + b, 3, 5)
print(result) # 输出: 8
# 函数列表
def process_all(funcs: List[Callable[[int], int]], value: int) -> List[int]:
return [f(value) for f in funcs]
# 使用
operations = [lambda x: x * 2, lambda x: x ** 2, lambda x: x + 10]
results = process_all(operations, 5)
print(results) # 输出: [10, 25, 15]
高级类型注解
NamedTuple
from typing import NamedTuple
class Point(NamedTuple):
x: int
y: int
z: int = 0 # 默认值
p = Point(1, 2)
print(p) # 输出: Point(x=1, y=2, z=0)
# 访问字段
print(p.x, p.y, p.z) # 输出: 1 2 0
TypedDict
from typing import TypedDict
class StudentDict(TypedDict):
name: str
age: int
grades: List[float]
student: StudentDict = {
"name": "Alice",
"age": 20,
"grades": [90.5, 85.0, 92.0]
}
Literal类型
from typing import Literal
def set_direction(direction: Literal["north", "south", "east", "west"]) -> None:
print(f"Moving {direction}")
set_direction("north") # 正确
# set_direction("up") # 类型错误
Protocol(协议)
Protocol用于定义结构化类型,类似于其他语言的接口。
from typing import Protocol, runtime_checkable
@runtime_checkable
class Drawable(Protocol):
def draw(self) -> str: ...
class Circle:
def draw(self) -> str:
return "Drawing circle"
class Square:
def draw(self) -> str:
return "Drawing square"
def draw_shape(shape: Drawable) -> str:
return shape.draw()
# 使用
circle = Circle()
square = Square()
print(draw_shape(circle)) # 输出: Drawing circle
print(draw_shape(square)) # 输出: Drawing square
# 检查协议
print(isinstance(circle, Drawable)) # 输出: True
类型检查工具
mypy
# 安装mypy
pip install mypy
# 运行类型检查
mypy your_script.py
Pyright
# 安装pyright
pip install pyright
# 运行类型检查
pyright your_script.py
实际应用案例
from typing import List, Dict, Optional, Union
# 1. 数据验证
def validate_email(email: str) -> bool:
return "@" in email and "." in email
# 2. 数据处理
def process_data(data: List[Dict[str, Union[str, int]]]) -> List[str]:
return [str(item["name"]) for item in data if "name" in item]
# 3. 配置管理
class Config(TypedDict):
database_url: str
debug: bool
port: int
def load_config(config: Config) -> None:
print(f"Database: {config['database_url']}")
print(f"Debug: {config['debug']}")
print(f"Port: {config['port']}")
最佳实践
- 从简单类型开始,逐步添加复杂类型
- 使用
Optional代替Union[X, None] - 为公共API编写类型注解
- 使用
TypeVar创建可重用的类型 - 定期运行类型检查器
类型注解虽然不是强制性的,但能显著提高代码质量和开发效率。