← [ BACK_TO_NOTES ]

Python 可变性、身份与拷贝

用对象身份、相等与可变性解释共享副作用;浅拷贝与深拷贝的边界与选用。

#concept #growing #dev #python #python

[!info] related notes

Python 可变性、身份与拷贝

这个概念为什么出现

“我只改了局部变量,为什么外面的订单也变了?”——根因几乎总是:多个名字绑定同一可变对象。本篇把 is/==、可变/不可变、浅/深拷贝钉成可检查模型。

[!abstract] 一句话理解 is 比身份、== 按类型协议比较相等;赋值共享对象,浅拷贝共享内层引用。deepcopy 按类型的拷贝协议递归处理对象图,不是任意资源的完整隔离保证。

最小可运行示例

先把示例放进业务场景,再看代码:

场景:克隆购物车草稿做 A/B 运费试算

结算要复制购物车:改副本行项目不应污染原购物车;若只浅拷贝,内层 list 仍共享。

# cart_copy_demo.py
# 业务意图:对比别名、浅拷贝、深拷贝对购物车的影响。
# 教学点:
# - is vs ==;
# - copy.copy 浅拷贝;
# - copy.deepcopy 深拷贝。

import copy


def main() -> None:
    cart = {"user": "u1", "items": ["SKU-1", "SKU-2"]}
    alias = cart
    shallow = copy.copy(cart)
    deep = copy.deepcopy(cart)

    alias["user"] = "u-alias"
    shallow["items"].append("SKU-X")  # 影响原 cart.items
    deep["items"].append("SKU-DEEP")

    print("same cart is alias?", cart is alias)
    print("cart == shallow?", cart == shallow)
    print("cart items:", cart["items"])
    print("shallow items:", shallow["items"])
    print("deep items:", deep["items"])
    print("cart user:", cart["user"])


if __name__ == "__main__":
    main()

建议运行:

python cart_copy_demo.py

期望输出:

same cart is alias? True
cart == shallow? False
cart items: ['SKU-1', 'SKU-2', 'SKU-X']
shallow items: ['SKU-1', 'SKU-2', 'SKU-X']
deep items: ['SKU-1', 'SKU-2', 'SKU-DEEP']
cart user: u-alias

结合场景再看三个关注点

  1. 别名改 user 直接改原对象。
  2. 浅拷贝复制了 dict 壳,但 items list 仍共享。
  3. 深拷贝后的追加不影响原购物车。

核心概念与准确模型

身份与相等

运算含义
a is b同一对象
a == b值相等(可重载)
a is NoneNone 哨兵推荐写法

可变性

  • int/str/tuple/frozenset 等对象本身不可变;tuple 固定元素引用,并不冻结其引用的 list 等对象。
  • 可变:list/dict/set/自定义对象字段...

拷贝

  • 浅:copy.copy / 切片 / dict.copy / list(...)
  • 深:copy.deepcopy

边界情况与反直觉行为

  1. 小整数驻留使 is 对字面量偶发 True——勿当业务逻辑。
  2. deepcopy 用 memo 处理循环和重复引用;复制后的对象图通常仍保留原图内部的共享关系,不是每个位置都生成独立对象。
  3. 自定义 __copy__/__deepcopy__ 可改变行为;函数、类常直接返回原对象,文件、锁等资源也不能靠 deepcopy 通用复制。

常见误区

[!warning] 常见误区:== 与 is 混用 错误理解:一样。
正确模型:值 vs 身份;None 用 is。

工程实践

  • 函数参数文档写明是否原地修改。
  • 需要隔离副作用时明确 copy 策略。
  • 性能敏感路径避免无脑 deepcopy。

本节总结

共享可变状态是 Python 最常见心智坑。先画“几个名字几个对象”,再决定要不要拷贝。

自测题

  1. 为什么浅拷贝后改 items 会影响原 cart?
  2. 什么场景选深拷贝?
参考答案
  1. 浅拷贝只复制外层 dict,内层 list 仍是同一对象。
  2. 已知支持拷贝的嵌套数据需要隔离原图修改时;应确认自定义拷贝协议和内部共享关系,资源句柄要另定所有权。

延伸阅读与资料来源

资料类型支撑内容
copy — Shallow and deep copy文档拷贝 API
Naming and binding规范绑定
创建于 2026/7/15 更新于 2026/10/6
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本