python中类型标注的实现示例

 更新时间:2026年09月02日 08:23:32   作者:求道於盲  
本文主要介绍了python中类型标注的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

类型标注 = 给变量、参数、返回值写上类型说明
不会在运行时强制检查,主要给 IDE / 类型检查工具用,用来:

  • 写代码时自动补全、提示参数
  • 提前发现「传错类型」这类问题

为什么需要

没有标注时,调用方不知道该传什么,也容易写出「能跑但不符合预期」的代码:

# 问题:参数类型不明确
def add(a, b):
    return a + b

# 调用者不知道应该传什么类型
add(1, 2)        # 3
add("1", "2")    # "12"  —— 这也是合法的,但可能不是预期行为
add([1], [2])    # [1, 2]  —— 同样合法

# 没有类型提示,难以在编码时发现错误

基础写法

变量

# 声明变量的类型
name: str = "Alice"
age: int = 25
pi: float = 3.14
is_active: bool = True

# 没有初始值
value: int
value = 10

# Python 是动态语言,类型标注不会强制约束
x: int = "hello"  # 不会报错,但类型检查工具会提示

要点:写了 x: int,运行时照样可以塞字符串;要靠类型检查工具(或 IDE)才会报警。

函数

格式:参数: 类型,返回值写在 -> 后面。

def greet(name: str, age: int) -> str:
    """函数参数和返回值的类型标注"""
    return f"{name} 今年 {age} 岁

# 调用
greet("Alice", 25)        # 正确
greet("Alice", "25")      # 运行不会报错,但类型检查会警告

如果函数永远不会正常返回(比如直接退出程序),用 NoReturn:

from typing import NoReturn

def exit_program() -> NoReturn:
    """表示函数永远不会正常返回"""
    import sys
    sys.exit(1)

常用复合类型

Optional 和 Union

Optional:可能有值,也可能没有

Optional[X] = 要么是 X,要么是 None。

下面三种写法意思完全一样:

Optional[str]
Union[str, None]
str | None          # Python 3.10+

典型场景:查找用户 —— 找到返回名字,找不到返回 None:

from typing import Optional, Union


# Optional:值可以是某个类型,也可以是 None
def find_user(user_id: int) -> Optional[str]:
    """返回用户名,找不到时返回 None"""
    if user_id <= 0:
        return None
    return f"User_{user_id}"

调用时先判断是不是 None,再当字符串用:

name = find_user(1)
if name is None:
    print("没找到")
else:
    print(name)  # 这里才是确定的 str

Union:多种类型之一

Union[A, B]:可以是 A,也可以是 B。

# Union:值可以是多种类型之一
def parse_value(value: str) -> Union[int, float, str]:
    """尝试将字符串转换为数字,失败则返回原字符串"""
    try:
        if "." in value:
            return float(value)
        return int(value)
    except ValueError:
        return value

新写法也可写成:int | float | str(Python 3.10+)

容器类型

在 List、Dict 等后面用 [] 写明里面装什么:

from typing import List, Dict, Tuple, Set


# 列表:元素类型
scores: List[int] = [85, 90, 78]
names: List[str] = ["Alice", "Bob", "Charlie"]


# 字典:键类型, 值类型
student_scores: Dict[str, int] = {
    "Alice": 85,
    "Bob": 90,
}


# 元组:固定长度,每个位置类型可不同
point: Tuple[int, int] = (10, 20)
person: Tuple[str, int, bool] = ("Alice", 25, True)


# 集合:元素类型
tags: Set[str] = {"python", "typing", "type-hints"}

Any 和类型别名

  • Any:随便什么类型都行(等于几乎不检查,少用)
  • 类型别名:给复杂类型起个好记的名字
from typing import Any, TypeAlias


# Any:任意类型,相当于没有类型约束
def log_data(data: Any) -> None:
    print(f"数据: {data}")


# 类型别名,让复杂类型更易读
Vector: TypeAlias = List[float]
Matrix: TypeAlias = List[List[float]]


def dot_product(v1: Vector, v2: Vector) -> float:
    """计算两个向量的点积"""
    return sum(a * b for a, b in zip(v1, v2))

类里怎么标

  • 方法参数、返回值照常写
  • Self:返回「自己这个类型的实例」
  • 类还没定义完就要引用自己时,可写成字符串 "Point"
from typing import Self


class Point:
    def __init__(self, x: float, y: float) -> None:
        self.x = x
        self.y = y

    def move(self, dx: float, dy: float) -> Self:
        """返回移动后的新点"""
        return Point(self.x + dx, self.y + dy)

    def distance_to(self, other: "Point") -> float:
        """计算到另一个点的距离"""
        return ((self.x - other.x) ** 2 + (self.y - other.y) ** 2) ** 0.5


# 使用
p1 = Point(0, 0)
p2 = Point(3, 4)
print(p1.distance_to(p2))  # 5.0

泛型

为什么需要泛型?

假设有一个函数,取出列表的第一个元素:

# 不用泛型:返回类型丢失了
def get_first(items):
    return items[0]

# 你无法知道返回的到底是什么类型

有了泛型:输入什么类型,输出就是什么类型,类型信息不会丢。

传统写法(Python 3.12 之前)

需要两个核心组件:TypeVar 和 Generic。

TypeVar — 类型变量

T 代表「未来某个具体类型」,实际使用时才会被确定(类似数学里的未知数 x):

from typing import TypeVar

T = TypeVar('T')  # 定义一个类型变量

泛型函数

from typing import TypeVar, List

T = TypeVar('T')

def get_first_item(lst: List[T]) -> T:
    return lst[0]

# 调用时,类型自动推断
num = get_first_item([1, 2, 3])       # num 的类型是 int
text = get_first_item(['a', 'b', 'c']) # text 的类型是 str

泛型类

from typing import TypeVar, Generic

T = TypeVar('T')

class Box(Generic[T]):
    def __init__(self, content: T):
        self.content = content

    def get(self) -> T:
        return self.content

# 使用
int_box = Box(42)          # Box[int]
str_box = Box("hello")     # Box[str]

现代写法(Python 3.12+)

可以直接在类 / 函数名后面声明类型参数,不必再单独写 TypeVar + Generic:

# 以前
from typing import TypeVar, Generic
T = TypeVar('T')
class Box(Generic[T]):
    def get(self) -> T: ...

# 现在(Python 3.12+)
class Box[T]:
    def get(self) -> T: ...

# 函数也可以这样写
def get_first[T](lst: list[T]) -> T:
    return lst[0]

更接近 Java / C# 的写法,类型参数不再游离在类 / 函数外面。

TypeVar 的三种约束方式

1. 无约束(任意类型)

T = TypeVar('T')  # 可以是任何类型

2. bound 约束(必须是某类型的子类)

S = TypeVar('S', bound=str)  # 必须是 str 或其子类

def print_capitalized(x: S) -> S:
    print(x.capitalize())
    return x

3. 值约束(只能是指定的几种类型之一)

A = TypeVar('A', str, bytes)  # 只能是 str 或 bytes

def concatenate(x: A, y: A) -> A:
    return x + y

concatenate("hello", "world")  # OK,返回 str
concatenate(b"foo", b"bar")    # OK,返回 bytes
# concatenate("foo", b"bar")   # 类型检查报错,不能混用

日常写业务代码,多数时候用 list[int]、str | None 就够了。
自己写「输入什么类型、输出就保持什么类型」的函数 / 类时,才需要泛型。

Callable:参数本身是函数

Callable[[参数类型...], 返回类型] 用来标注「回调函数长什么样」。

from typing import Callable


def execute_callback(
    callback: Callable[[int, int], int],
    a: int,
    b: int
) -> int:
    """执行回调函数"""
    return callback(a, b)


# 使用
result = execute_callback(lambda x, y: x + y, 3, 5)
print(result)  # 8

读法:Callable[[int, int], int] = 接收两个 int,返回一个 int 的函数。

实际能干什么

1. 用 TypedDict 描述「字典长什么样」

普通 dict 太松;TypedDict 可以规定每个 key 的类型:

from typing import TypedDict


class UserResponse(TypedDict):
    """API 返回的用户数据结构"""
    id: int
    name: str
    email: str
    is_active: bool


def get_user(user_id: int) -> UserResponse:
    return {
        "id": user_id,
        "name": "Alice",
        "email": "alice@example.com",
        "is_active": True,
    }

某个字段可以不提供时,用 NotRequired:

from typing import TypedDict, NotRequired


class Product(TypedDict):
    id: int
    name: str
    description: NotRequired[str]  # 可选字段,可以不提供

# 两种写法都合法
p1: Product = {"id": 1, "name": "手机"}
p2: Product = {"id": 2, "name": "电脑", "description": "高性能笔记本"}

反过来,希望默认所有字段都可选时,用 total=False:

class Config(TypedDict, total=False):
    debug: bool
    retry_times: int
    timeout: float

# 所有字段都可以不提供
c: Config = {}

到此这篇关于python中类型标注的实现示例的文章就介绍到这了,更多相关python 类型标注内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python极简代码实现杨辉三角示例代码

    Python极简代码实现杨辉三角示例代码

    杨辉三角形因为其形式简单,又有一定的使用价值,因此是入门编程题中被用的最多的,也是很好的语言实例标的。这篇文章就给大家介绍了Python极简代码实现杨辉三角的方法,文章给出了详细的示例代码和解释,对大家理解很有帮助,感兴趣的朋友们下面来一起看看吧。
    2016-11-11
  • Python中安装库的常用方法介绍

    Python中安装库的常用方法介绍

    大家好,本篇文章主要讲的是Python中安装库的常用方法介绍,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2022-01-01
  • 基于python自制一个软件工具安装包

    基于python自制一个软件工具安装包

    这篇文章主要为大家详细介绍了一种将软件工具打包为独立安装程序的方法,核心思路是将目录文件转换为Base64编码的JSON文件,再通过解码程序还原为可执行文件,感兴趣的可以了解下
    2025-08-08
  • Python编写简单的HTML页面合并脚本

    Python编写简单的HTML页面合并脚本

    这篇文章主要介绍了Python编写简单的HTML页面合并脚本的相关资料,需要的朋友可以参考下
    2016-07-07
  • python 怎样将dataframe中的字符串日期转化为日期的方法

    python 怎样将dataframe中的字符串日期转化为日期的方法

    这篇文章主要介绍了python 怎样将dataframe中的字符串日期转化为日期的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • Keras 利用sklearn的ROC-AUC建立评价函数详解

    Keras 利用sklearn的ROC-AUC建立评价函数详解

    这篇文章主要介绍了Keras 利用sklearn的ROC-AUC建立评价函数详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-06-06
  • pyenv管理多个版本python的完整指南

    pyenv管理多个版本python的完整指南

    这篇文章主要为大家详细介绍了pyenv管理多个版本python的完整指南,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以了解下
    2025-12-12
  • PyTorch中的train()、eval()和no_grad()的使用

    PyTorch中的train()、eval()和no_grad()的使用

    本文主要介绍了PyTorch中的train()、eval()和no_grad()的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • Python使用googletrans报错的解决方法

    Python使用googletrans报错的解决方法

    这篇文章主要给大家介绍了关于Python使用googletrans报错的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-09-09
  • django 数据库 get_or_create函数返回值是tuple的问题

    django 数据库 get_or_create函数返回值是tuple的问题

    这篇文章主要介绍了django 数据库 get_or_create函数返回值是tuple的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-05-05

最新评论