namedtuple适合轻量只读场景,如配置常量、函数多返回值、字典key;dataclass适用于需可变、默认值、方法、序列化的开发需求;性能敏感且字段固定时可选TypedDict或手写__slots__类。

用 namedtuple 定义不可变结构体,适合轻量只读场景
当你要建一个类似 C 的 struct Point { int x; int y; },且确定字段不会改、不需方法、不需默认值,namedtuple 是最轻的选。它生成的是类,但实例不可变,内存紧凑,访问快。
常见错误是误以为能赋值:p = Point(1, 2); p.x = 3 会抛 AttributeError: can't set attribute —— 这不是 bug,是设计如此。
- 定义方式:
from collections import namedtuple; Point = namedtuple("Point", ["x", "y"]) - 支持类型提示(Python 3.9+):
Point = namedtuple("Point", ["x: int", "y: int"]),但运行时不校验 - 字段名不能以 underscore 开头,否则会被忽略(如
["_id", "name"]中_id不进实例) - 不支持默认值;若需要,得用
_replace()构造新实例,比如p._replace(y=5)
用 dataclass 定义可变结构体,更接近真实开发需求
绝大多数时候你其实想要的是“可赋值 + 有默认值 + 能加方法 + 支持类型检查”的结构体,@dataclass 就是为此生的。它比 namedtuple 更灵活,也更贴近 C struct 的使用直觉(比如初始化后改字段)。
容易踩的坑是忘了加 __slots__ = True —— 默认 dataclass 实例带 __dict__,内存开销比 namedtuple 大不少,尤其字段多、实例多时。
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
立即学习“Python免费学习笔记(深入)”;
- 基础用法:
from dataclasses import dataclass; @dataclass; class Point: x: int; y: int - 设默认值:
x: int = 0,注意所有无默认值字段必须在有默认值字段之前 - 禁用
__dict__降内存:@dataclass(slots=True)(Python 3.10+) - 想支持比较(
==)或排序,加参数:@dataclass(eq=True, order=False),默认eq=True,order=False
什么时候该选 namedtuple,什么时候必须用 dataclass
别凭感觉选。关键看三点:是否要改字段、是否要默认值、是否在意内存/启动速度。
- 选
namedtuple:配置项常量(如HTTPStatus = namedtuple("HTTPStatus", ["code", "phrase"])...)、函数返回多个值的容器、做字典 key(因不可变可哈希) - 选
dataclass:API 响应解析(字段常有默认 null 值)、需要校验逻辑(__post_init__)、要序列化为 JSON(asdict()直接支持)、字段可能动态增删(虽然不推荐,但__dict__允许) - 性能敏感场景(如百万级几何点计算),
namedtuple创建快、占内存小;但若要频繁更新字段,dataclass+slots=True反而更稳,避免namedtuple._replace()不断新建对象的开销
dataclass 和 namedtuple 都不满足?考虑 TypedDict 或手写 __slots__ 类
如果结构体只是临时传参、不做实例方法、又需要部分字段可选(比如前端传来的 patch 数据),TypedDict 比两者都合适——它只是类型提示,运行时是普通 dict,零开销,且支持 total=False 表示字段可选。
而如果你对内存和访问速度极端敏感(比如高频金融 tick 处理),且字段固定、绝不扩展,手写带 __slots__ 的空类比 dataclass(slots=True) 少一层装饰器开销,字段访问也略快一点。
from typing import TypedDict; class User(TypedDict, total=False): name: str; age: int- 手写
__slots__示例:class Point: __slots__ = ("x", "y"); def __init__(self, x: int, y: int): self.x, self.y = x, y -
TypedDict不能被实例化,只用于类型检查;手写__slots__类没自动生成__repr__或__eq__,得自己补
namedtuple 和裸 dataclass 都会迅速变得难维护。这时候该上 pydantic.BaseModel,而不是硬撑。

















