Python 类型提示(Type Hints)
所属分类 python
浏览量 15
Python 类型提示优点:
更好的代码可读性
早期错误检测
更好的IDE支持
提高代码质量
Python 3.10+ 提供了更简洁的语法,
建议使用新版本以获得更好的类型提示体验
1. 基础类型注解
1.1 基本类型
# 基本类型注解
def greet(name: str) -> str:
return f"Hello, {name}"
def add(a: int, b: int) -> int:
return a + b
def is_active(status: bool) -> bool:
return status
def calculate_price(price: float, tax_rate: float = 0.1) -> float:
return price * (1 + tax_rate)
# 使用示例
result: str = greet("Alice")
total: int = add(10, 20)
active: bool = is_active(True)
final_price: float = calculate_price(100.0)
1.2 变量注解
# 变量类型注解
name: str = "John"
age: int = 30
is_student: bool = False
height: float = 175.5
# 类型推断(Python 3.6+)
from typing import TypeVar
T = TypeVar('T')
def first_element(items: list[T]) -> T:
return items[0]
2. 容器类型注解
2.1 列表、元组、字典、集合
from typing import List, Dict, Set, Tuple, Optional, Union
# 列表注解
def process_numbers(numbers: List[int]) -> List[float]:
return [n * 1.5 for n in numbers]
# 字典注解
def process_students(students: Dict[str, int]) -> Dict[str, str]:
return {name: f"Grade: {grade}" for name, grade in students.items()}
# 集合注解
def unique_items(items: Set[str]) -> int:
return len(items)
# 元组注解(固定长度)
def get_coordinates() -> Tuple[float, float]:
return (40.7128, -74.0060)
# 元组注解(可变长度)
def process_data(data: Tuple[int, ...]) -> float: # 任意数量的int
return sum(data) / len(data)
# 使用示例
numbers: List[int] = [1, 2, 3, 4, 5]
students: Dict[str, int] = {"Alice": 90, "Bob": 85}
unique_names: Set[str] = {"Alice", "Bob", "Charlie"}
coordinates: Tuple[float, float] = (40.7128, -74.0060)
2.2 更现代的语法(Python 3.9+)
# Python 3.9+ 使用内置类型
def process_numbers(numbers: list[int]) -> list[float]:
return [n * 1.5 for n in numbers]
def process_dict(data: dict[str, int]) -> dict[str, str]:
return {k: str(v) for k, v in data.items()}
def get_items() -> tuple[int, str, bool]:
return (1, "hello", True)
3. 复杂类型注解
3.1 Optional 和 Union
from typing import Optional, Union
# Optional 表示可能为 None
def find_user(user_id: int) -> Optional[Dict[str, str]]:
if user_id > 0:
return {"id": str(user_id), "name": "John"}
return None
# Union 表示多种类型
def process_input(value: Union[int, str, List[int]]) -> str:
if isinstance(value, int):
return f"整数: {value}"
elif isinstance(value, str):
return f"字符串: {value}"
else:
return f"列表: {value}"
# Python 3.10+ 使用 | 语法
def process_input_v2(value: int | str | list[int]) -> str:
return str(value)
# 使用示例
user: Optional[dict] = find_user(123)
result: str = process_input([1, 2, 3])
3.2 Any 和 TypeVar
from typing import Any, TypeVar, Generic
# Any 表示任意类型
def log_message(message: Any) -> None:
print(f"[LOG]: {message}")
# TypeVar 用于泛型
T = TypeVar('T')
def get_first(items: list[T]) -> T:
return items[0]
# 多个 TypeVar
K = TypeVar('K')
V = TypeVar('V')
def get_value(dictionary: dict[K, V], key: K) -> V:
return dictionary[key]
# 带约束的 TypeVar
Number = TypeVar('Number', int, float)
def double(value: Number) -> Number:
return value * 2
# 使用示例
first_num: int = get_first([1, 2, 3])
first_str: str = get_first(["a", "b", "c"])
value: int = get_value({"a": 1, "b": 2}, "a")
4. 函数类型注解
4.1 Callable
from typing import Callable, List
# 函数作为参数
def apply_function(
func: Callable[[int, int], int],
a: int,
b: int
) -> int:
return func(a, b)
# 返回函数
def create_multiplier(factor: int) -> Callable[[int], int]:
def multiplier(x: int) -> int:
return x * factor
return multiplier
# 使用示例
def add(x: int, y: int) -> int:
return x + y
result: int = apply_function(add, 10, 20)
multiply_by_3: Callable[[int], int] = create_multiplier(3)
print(multiply_by_3(5)) # 15
4.2 Lambda 函数类型
from typing import Callable
# lambda 函数类型
sorter: Callable[[int, int], int] = lambda x, y: x - y
numbers = [5, 2, 8, 1]
sorted_numbers = sorted(numbers, key=lambda x: x)
# 高阶函数
def filter_list(
items: List[int],
predicate: Callable[[int], bool]
) -> List[int]:
return [item for item in items if predicate(item)]
# 使用示例
even_numbers = filter_list([1, 2, 3, 4, 5], lambda x: x % 2 == 0)
5. 类相关的类型注解
5.1 类方法和属性
from typing import ClassVar, Final
class User:
# 类变量注解
count: ClassVar[int] = 0
MAX_AGE: Final[int] = 150
def __init__(self, name: str, age: int):
self.name: str = name
self.age: int = age
User.count += 1
@classmethod
def get_count(cls) -> int:
return cls.count
def get_info(self) -> str:
return f"{self.name}, {self.age} years old"
# 类型注解返回自身类型
class Node:
def __init__(self, value: int):
self.value: int = value
self.next: Optional['Node'] = None
def set_next(self, node: 'Node') -> None:
self.next = node
5.2 继承和多态
from typing import Type
class Animal:
def speak(self) -> str:
return "Animal sound"
class Dog(Animal):
def speak(self) -> str:
return "Woof!"
class Cat(Animal):
def speak(self) -> str:
return "Meow!"
def animal_sound(animal: Animal) -> str:
return animal.speak()
# 工厂模式中的类型注解
def create_animal(animal_type: str) -> Animal:
if animal_type == "dog":
return Dog()
elif animal_type == "cat":
return Cat()
else:
return Animal()
# 使用示例
dog: Animal = Dog()
cat: Animal = Cat()
print(animal_sound(dog)) # Woof!
print(animal_sound(cat)) # Meow!
6. 高级类型注解
6.1 Literal 和 TypedDict
from typing import Literal, TypedDict, List
# Literal 用于字面值
def set_status(status: Literal["active", "inactive", "pending"]) -> None:
print(f"Status set to: {status}")
# TypedDict 用于结构化字典
class UserData(TypedDict):
name: str
age: int
email: Optional[str]
tags: List[str]
def process_user(data: UserData) -> str:
return f"Processing {data['name']}, age {data['age']}"
# 使用示例
set_status("active") # 只能传递这三个值之一
user_info: UserData = {
"name": "Alice",
"age": 25,
"email": "alice@example.com",
"tags": ["premium", "active"]
}
process_user(user_info)
6.2 Protocol(结构类型)
from typing import Protocol, runtime_checkable
# Protocol 定义接口
class Drawable(Protocol):
def draw(self) -> str:
...
class Circle:
def draw(self) -> str:
return "Drawing Circle"
class Rectangle:
def draw(self) -> str:
return "Drawing Rectangle"
def render(shape: Drawable) -> None:
print(shape.draw())
# 使用示例
circle: Drawable = Circle()
rectangle: Drawable = Rectangle()
render(circle) # Drawing Circle
render(rectangle) # Drawing Rectangle
7. 实战示例
7.1 API 响应处理
from typing import TypedDict, List, Optional
from datetime import datetime
class UserResponse(TypedDict):
id: int
username: str
email: str
is_active: bool
created_at: str
last_login: Optional[str]
class PaginatedResponse(TypedDict):
count: int
next: Optional[str]
previous: Optional[str]
results: List[UserResponse]
def process_api_response(response: PaginatedResponse) -> List[str]:
"""处理API响应数据"""
usernames: List[str] = []
for user in response['results']:
if user['is_active']:
usernames.append(user['username'])
return usernames
# 模拟API响应
api_response: PaginatedResponse = {
"count": 2,
"next": None,
"previous": None,
"results": [
{
"id": 1,
"username": "alice",
"email": "alice@example.com",
"is_active": True,
"created_at": "2024-01-01",
"last_login": "2024-01-14"
},
{
"id": 2,
"username": "bob",
"email": "bob@example.com",
"is_active": False,
"created_at": "2024-01-02",
"last_login": None
}
]
}
active_users = process_api_response(api_response)
print(f"活跃用户: {active_users}")
7.2 数据验证装饰器
from typing import Callable, TypeVar, Any
from functools import wraps
R = TypeVar('R')
def type_check(func: Callable[..., R]) -> Callable[..., R]:
"""类型检查装饰器"""
@wraps(func)
def wrapper(*args: Any, **kwargs: Any) -> R:
# 获取函数的类型提示
annotations = func.__annotations__
# 检查参数类型
for i, (arg_name, arg_type) in enumerate(
list(annotations.items())[:-1] # 排除返回类型
):
if i < len(args):
arg_value = args[i]
if not isinstance(arg_value, arg_type):
raise TypeError(
f"参数 '{arg_name}' 应该是 {arg_type} 类型,"
f"但得到的是 {type(arg_value)}"
)
# 调用原函数
result = func(*args, **kwargs)
# 检查返回类型
return_type = annotations.get('return')
if return_type and not isinstance(result, return_type):
raise TypeError(
f"返回值应该是 {return_type} 类型,"
f"但得到的是 {type(result)}"
)
return result
return wrapper
# 使用装饰器
@type_check
def add_numbers(a: int, b: int) -> int:
return a + b
# 测试
try:
result = add_numbers(10, 20) # 正确
print(f"结果: {result}")
result = add_numbers("10", 20) # 会抛出 TypeError
except TypeError as e:
print(f"类型错误: {e}")
8. 工具和最佳实践
8.1 静态类型检查工具
# 安装 mypy
pip install mypy
# 运行 mypy 检查
mypy your_script.py
# 在配置文件中启用严格模式
# pyproject.toml 或 mypy.ini
"""
[tool.mypy]
python_version = "3.9"
warn_return_any = true
warn_unused_configs = true
strict = true
"""
8.2 最佳实践
逐步添加类型:不需要一次性为所有代码添加类型
使用合适的工具:mypy, pyright, pylance
避免过度使用 Any:尽量使用具体类型
保持一致性:团队使用相同的类型检查配置
文档补充:类型提示不能完全替代文档
上一篇
下一篇
springboot环境变量替换配置文件值
葛兰威尔均线八大法则
python 发送http请求获取行情数据实例
python 属性访问器
Python知识点及代码示例