Python 可变性、身份与拷贝

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

#type / concept #status / growing #tech / dev #resource / python #tech / lang / python

[!info] 关联笔记

Python 可变性、身份与拷贝

这个概念为什么出现

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

[!abstract] 一句话理解 is 比身份、== 比值;可变对象的原地修改对所有别名可见;浅拷贝只复制容器壳,深拷贝递归复制。

最小可运行示例

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

场景:克隆购物车草稿做 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/...(对象值不改)
  • 可变:list/dict/set/自定义对象字段...

拷贝

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

边界情况与反直觉行为

  1. 小整数驻留使 is 对字面量偶发 True——勿当业务逻辑。
  2. deepcopy 遇循环引用可处理,但成本高。
  3. 自定义对象默认浅拷贝共享子对象。

常见误区

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

工程实践

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

本节总结

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

自测题

  1. 为什么浅拷贝后改 items 会影响原 cart?
  2. 什么场景选深拷贝?
参考答案
  1. 浅拷贝只复制外层 dict,内层 list 仍是同一对象。
  2. 嵌套可变结构需要完全隔离修改时(如试算草稿)。

延伸阅读与资料来源

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