空列表优先用[]而非list(),语义清晰、性能更优;用*创建嵌套列表时易因浅拷贝出错,应改用列表推导式;预分配长度比反复append更快但需确知最终大小。

空列表用 [],别用 list() 除非真需要动态类型
绝大多数时候,[] 是更直接、更快、更 Pythonic 的空列表写法。list() 看似“标准”,但会触发函数调用开销,且在某些上下文中容易误导——比如你以为它能传参初始化,结果发现 list(5) 报 TypeError: 'int' object is not iterable。
常见错误现象:
— 在循环里反复写 list() 初始化,性能比 [] 低约 15–20%(CPython 3.12 测试)
— 想初始化带默认值的列表,误写成 list(0) * 5,结果报错
- 初始化空容器优先用
[],语义清晰、启动快 - 只有当你需要从可迭代对象构造列表(如
list(range(3))或list("abc"))时,才用list() - 不要为了“看起来统一”而把所有初始化都套
list(),这是反模式
[0] * n 创建的是浅拷贝列表,嵌套结构会翻车
用乘法扩展列表很方便,但只适用于不可变元素(如 int、str、None)。一旦元素是可变对象(比如字典、列表、自定义类实例),所有位置指向同一内存地址。
使用场景:
— 快速生成一维数值占位符(如缓存数组、计数器)
— 初始化全 None 或全 False 的布尔标记列表
典型翻车示例:matrix = [[]] * 3; matrix[0].append(1) → [ [1], [1], [1] ],不是你想要的 [ [1], [], [] ]
华为云 Python SDK 查询工具。自动发现已安装 SDK 的服务包、Client类、API 方法、入参详情、类信息(__init__ 参数、属性、类型、描述),支持关键字搜索,快速定位目标 API 使用方法。
- 要创建独立子列表,改用列表推导式:
[[] for _ in range(3)] -
[0] * 5和[0 for _ in range(5)]效果一样,但前者更快;后者只在需深隔离时才必须 - 乘法不检查右侧是否可变,Python 默认不做深拷贝——这是设计选择,不是 bug
初始化带默认值的二维列表,别靠 * n 嵌套
想建一个 3 行 4 列、全填 0 的二维列表?直接写 [[0] * 4] * 3 看似简洁,实则危险:外层数组是三个相同引用,改任意一行都会同步到其他行。
错误现象:grid = [[0] * 4] * 3; grid[0][0] = 99 → grid[1][0] 和 grid[2][0] 也变成 99
- 安全写法只有两种:
[[0 for _ in range(4)] for _ in range(3)](推荐)或用 NumPy:np.zeros((3, 4), dtype=int) - 如果只是临时测试、确定不会修改内容,
* n嵌套可用,但代码里得加注释说明“此处无副作用” - 没有“又快又安全”的单行乘法语法——这是 Python 对可变对象一致性的坚持,不是缺陷
初始化空列表后追加 vs 预分配长度,性能差在哪
如果你已知最终长度(比如读取固定行数的文件),预分配 [None] * n 再按索引赋值,通常比反复 .append() 快 10–30%,尤其在大列表(>10k 元素)场景。但前提是:你真的知道长度,且不依赖 append 的动态扩容逻辑。
性能影响关键点:
— .append() 触发底层数组扩容(通常是 1.125 倍增长),有少量内存重分配成本
— 预分配避免扩容,但多占一次内存(若中途 break,可能浪费)
— 小列表(
- 确定长度且顺序填充 → 用预分配:
res = [None] * n; for i in range(n): res[i] = calc(i) - 长度不确定、边算边加、或需插入中间 → 老实用
.append() - 别为了“看起来高效”强行预分配,可读性和正确性永远优先
最常被忽略的一点:列表乘法和预分配都是基于对象引用的,不是基于值的复制。哪怕你初始化的是 0 或 None,只要后续替换成可变对象(比如把某个位置改成 {}),那个位置就脱离了“值安全”范畴——这时候,之前的初始化方式是否还适用,得重新判断。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










