Type Hints
from typing import .... 是Python 中用于类型提示(Type Hints)的常用导入语句。它们帮助开发者和工具(如 IDE、mypy 等)理解变量、函数参数和返回值的预期类型,提高代码可读性和健壮性。
在构建AI系统(MCP,agent)时, 正确的类型提示可以更好让LLM调用MCP和agent工具
List
表示一个可读写的列表(list),可以指定列表中元素的类型。
List[元素类型]
from typing import List
arr: List[int] = [1, 2, 3]
print(arr[0])
arr[0] = 5 # 在读写 list[T] 类型时不会出现任何错误提示
def get_names() -> List[str]:
return ["Alice", "Bob", "Charlie"]
def add_numbers(nums: List[int]) -> int:
return sum(nums)
print(get_names())
print(add_numbers(arr))
⚠️ 注意:从 Python 3.9 开始,可以直接使用内置的
list类型进行泛型标注(如list[str]),不再强制需要typing.List。但在旧版本(<3.9)或为了兼容性,仍常用List。
Sequence
表示一个只读的任何序列类型,包括 list、tuple、str、range 等(只要是实现了 __getitem__ 和 __len__ 的有序容器,所以在写Sequence[T]类型时会提示 not define __setitem__)。
适用于“只读”或“不需要修改”的场景。
Sequence[元素类型]
from typing import Sequence
arr: Sequence[str] = ["a", "b", "c"]
arr[0] = "d" # 代码可以正常运行,但编译器提示: Class 'Sequence' does not define '__setitem__', so the '[]' operator cannot be used on its instances
print(arr) # ["d", "b", "c"]
def print_items(items: Sequence[str]) -> None:
for item in items:
print(item)
# 合法
print_items(["a", "b", "c"]) # list
print_items(("a", "b", "c")) # tuple
print_items("hello world") # 字符串本身就是容器类型
# 不合法
print_items([1, 2, 3]) # 代码可以正常运行,但编译器会提示: Expected type 'Sequence[str]', got 'list[int]' instead
✅ 建议:如果你的函数只遍历或读取数据,不修改容器,优先使用
Sequence而不是List,这样更灵活。
Optional
表示某个值可以是某种类型,也可以是 None。
等价于 Union[T, None]。
Optional[类型]
from typing import Optional
def find_user(user_id: int) -> Optional[str]:
# 假设根据 ID 查找用户名,找不到返回 None
users = {1: "Alice", 2: "Bob"}
return users.get(user_id) # 可能返回 str 或 None
name: Optional[str] = find_user(3)
if name is not None:
print(f"Found: {name}")
def get_hobby(user_id: int) -> Optional[Sequence[str]]:
users = {1: ["a", "b"], 2: ["a", "b"]}
return users.get(user_id)
hobby: Optional[Sequence[str]] = get_hobby(3)
if hobby is not None:
print(f"Found: {hobby}")
✅ 使用场景:函数可能失败、字典查找、可选配置参数等。
📌 提示:Python 3.10+ 还支持更简洁的写法,例如
str | None代替Optional[str],但Optional仍然广泛使用且清晰。
Any
Any 表示任意类型。使用 Any 相当于“关闭”类型检查——它告诉类型检查器(如 mypy、PyCharm 等):“这个值可以是任何东西,不要报错”。
⚠️ 虽然方便,但应尽量避免滥用
Any,因为它会削弱类型系统的安全性。
使用场景
- 与动态数据交互(如 JSON 解析结果)
- 临时占位(待后续完善类型)
- 与未提供类型注解的第三方库交互
from typing import Any
def log_value(value: Any) -> None:
print(f"Value: {value}, type: {type(value)}")
log_value(42) # int
log_value("hello") # str
log_value([1, 2, 3]) # list
Dict
表示一个可读写的字典,指定键和值的类型
Dict[KeyType, ValueType]
📌 从 Python 3.9+ 开始,也可以直接用内置的
dict进行泛型标注(如dict[str, int]),但typing.Dict在旧版本中仍广泛使用。
from typing import Dict
config: Dict[str, str] = {
"host": "localhost",
"port": "8080" # 注意:这里值是 str,不是 int
}
def get_user_info() -> Dict[str, str]:
return {"name": "a", "age": "23"}
user_info: Dict[str, str] = get_user_info()
Dict 表示可变字典,如果只需要读取,也可以考虑用 Mapping(更通用,类似 Sequence vs List)。
TypedDict
TypedDict 用于定义具有固定键名和特定值类型的字典结构,特别适合表示 JSON 数据、配置对象、API 响应等。
与普通 Dict 不同,TypedDict 的每个键都有明确的名称和类型,支持 IDE 自动补全和类型检查。
from typing import TypedDict
class Person(TypedDict):
name: str
age: int
email: str
# 使用
p: Person = {
"name": "Alice",
"age": 30,
"email": "alice@example.com"
}
默认情况下,TypedDict 要求所有字段都必须存在(total=True)。如果某些字段是可选的,可以设置 total=False:
class Movie(TypedDict, total=False):
title: str
year: int
director: str # 可选
# 合法
m1: Movie = {"title": "Inception"}
m2: Movie = {"title": "Interstellar", "year": 2014, "director": "Nolan"}
案例
from typing import TypedDict, List
class ApiResponse(TypedDict):
status: str
data: List[Person]
response: ApiResponse = {
"status": "success",
"data": [
{"name": "Bob", "age": 25, "email": "bob@example.com"}
]
}
Literal
Literal用于限制变量或参数只能取某些特定的字面量值(literal values),比如固定的字符串、数字、布尔值等
from typing import Literal
var: Literal["red", "green", "blue"] = "red"
注意事项
-
值必须是字面量(literal):只能是
str,bytes,int,bool,enum成员,或None# ❌ 错误:变量不能作为 Literal 参数 mode = "read" x: Literal[mode] # 报错! -
大小写敏感
Literal["Read"] != Literal["read"] -
不要过度使用:如果选项很多或动态变化,考虑用
Enum或运行时验证。
🎯 一句话记住:当你想说“这个参数只能是这几个固定值之一”时,就用
Literal。
常见使用场景
1. 限制函数参数为特定选项(替代枚举或字符串常量)
from typing import Literal
def set_mode(mode: Literal["read", "write", "append"]) -> None:
if mode == "read":
print("Reading file...")
elif mode == "write":
print("Writing file...")
elif mode == "append":
print("Appending to file...")
# 合法调用
set_mode("read")
# 类型检查器会报错 ❌
# set_mode("delete") # 错误:'delete' 不在允许的字面量中
💡 这比写 mode: str 更安全,避免拼写错误或非法值。
2. 布尔字面量(有时用于区分行为)
虽然 bool 本身只有 True/False,但有时为了明确意图:
from typing import Literal
def enable_feature(flag: Literal[True]) -> None:
print("Feature enabled!")
# 只接受 True,不能传 False
enable_feature(True) # ✅
# enable_feature(False) # ❌ 类型错误
案例:
from typing import Literal, TypedDict
Method = Literal["GET", "POST", "PUT", "DELETE"]
class RequestConfig(TypedDict):
url: str
method: Method
timeout: int
def send_request(config: RequestConfig) -> None:
print(f"Sending {config['method']} request to {config['url']}")
# 正确
send_request({"url": "https://api.example.com", "method": "POST", "timeout": 10})
# 类型错误 ❌
# send_request({"url": "...", "method": "PATCH", ...}) # 'PATCH' 不被允许
Annotated
Annotated用于在保留主类型的同时,附加额外的元数据(metadata),而不会影响类型检查器对主类型的判断。
from typing import Annotated
VarType = Annotated[实际类型, 元数据1, 元数据2, ...]
- 第一个参数:是变量的真实类型(如
str,int,List[str]等),类型检查器(如 mypy)只关心这个。 - 后续参数:是任意数量的元数据(metadata),可以是字符串、类、验证函数、文档说明、序列化配置等,运行时可用,但不影响类型检查。
✅ 核心思想:“给类型加注释,而不改变类型本身”
示例:
from typing import Annotated
Username = Annotated[str, "用户名,长度 3-20 个字符"]
def create_user(name: Username) -> None:
print(f"Creating user: {name}")
# 类型检查器仍认为 name 是 str
# 但开发者或工具可以读取后面的说明
from typing import Annotated
from fastapi import FastAPI, Query
from pydantic import BaseModel
app = FastAPI()
# 使用 Annotated + Query 来定义 API 参数约束
@app.get("/items/")
def read_items(q: Annotated[str, Query(max_length=50, min_length=3)]):
return {"q": q}
# 在 Pydantic 模型中
class UserCreate(BaseModel):
name: Annotated[str, "用户真实姓名"]
age: Annotated[int, "年龄,必须 >= 0"] = 18
💡 这里
Query(...)就是一个元数据对象,FastAPI 会读取它来生成 OpenAPI 文档和做请求验证。

5万+

被折叠的 条评论
为什么被折叠?



