当前位置: 首页 > news >正文

Python 中可变对象的“引用赋值”特性——可变对象的“引用传递”

一、踩坑代码

某程序老鸟讲了一个故事:
“2019年夏天,我在做一个推荐系统的用户画像模块。当时写了这样的代码:

# 当时的蠢代码,现在想起来都脸红
default_preferences = []  # 想着所有用户共享一个默认偏好
users = {}
for user_id in user_ids:users[user_id] = default_preferences  # 妈的,大坑!
```python所有用户共享了同一个列表!用户A喜欢看动作片,结果用户B、C、D全都变成动作片爱好者了。线上故障持续了2个小时,被领导骂得狗血淋头。那天晚上我查了一夜的资料,才彻底搞懂Python的对象模型。”解释一下:
```python
# 1. 创建一个列表(内存地址假设为 0x123)
default_preferences = []  
# 2. 循环给 3 个用户赋值
user_ids = [1,2,3]
users = {}
for user_id in user_ids:users[user_id] = default_preferences  # 所有用户都指向 0x123 的列表# 3. 给用户1添加“动作片”偏好
users[1].append("动作片")  # 4. 查看所有用户的偏好——全变成了动作片!
print(users[1])  # ['动作片'](改的是 0x123 的列表)
print(users[2])  # ['动作片'](指向同一个 0x123)
print(users[3])  # ['动作片'](同样指向 0x123)

本质是:以为给每个用户“分配了一个新列表”,实际是“让所有用户共用同一个列表”——这就是线上故障的根源:用户A修改偏好,等于修改了所有人的偏好。

二、怎么改才对?(避免共享可变对象)

核心思路:给每个用户创建“独立的新列表”,而不是复用同一个列表的引用。有两种常见写法:

1. 循环内每次创建新列表(推荐)

在循环里直接定义空列表,每个用户拿到的都是内存中不同的新列表:

users = {}
for user_id in user_ids:# 每次循环都新建一个空列表(内存地址不同)users[user_id] = []  # 给用户1加偏好,只影响用户1
users[1].append("动作片")
print(users[1])  # ['动作片']
print(users[2])  # [](独立列表,不受影响)

2. 用列表的 copy() 方法(适合有默认值的场景)

如果默认偏好不是空列表(比如有默认值 ["喜剧片"]),可以用 copy() 复制一个新列表给每个用户:

# 有默认值的列表
default_preferences = ["喜剧片"]  
users = {}
for user_id in user_ids:# 复制一个新列表(内存地址不同),避免共享users[user_id] = default_preferences.copy()  # 给用户1加动作片,不影响其他人
users[1].append("动作片")
print(users[1])  # ['喜剧片', '动作片']
print(users[2])  # ['喜剧片'](默认值,未被修改)

三、为什么这个“坑”很容易踩?(新手常见误区)

很多人会误以为“赋值就是复制数据”,但忽略了“可变对象 vs 不可变对象”的区别:

  • 比如给整数赋值 a = 1; b = a; b = 2a 还是 1(不可变对象,赋值是副本);
  • 但给列表赋值 a = []; b = a; b.append(1)a 也会变成 [1](可变对象,赋值是引用)。

你的场景里,“想让所有用户有默认偏好”是合理需求,但错把“共享引用”当成了“共享默认值”——最终导致数据串用,线上故障。

总结

这段代码的“蠢”不是逻辑错,而是对 Python 可变对象的赋值机制理解不到位:

  • 可变对象(列表、字典等)赋值传递“引用”,不是“副本”;
  • 循环中给多个变量赋值同一个可变对象,会导致所有变量共享数据;
  • 解决办法:给每个用户创建独立的可变对象(循环内新建,或用 copy() 复制)。

这种坑很典型,很多新手(甚至工作几年的开发者)都踩过——吃一次线上故障的亏,对“引用传递”的理解就再也忘不掉了~

http://www.jsqmd.com/news/30375/

相关文章:

  • CSP-S 2025 游寄喵
  • Modbus协议分类及测试学习笔记
  • MarkDown初入
  • 英语_作文_8AU3_Curiosity
  • 习题-极大原理
  • 极大原理
  • P7. TensorBoard的使用(一)
  • 二分搜索优化DP(子序列问题)
  • 如何从手机内部恢复数据?2025年9大最佳手机数据恢复软件
  • 如何将数据从 Mac 硬盘恢复数据到电脑:所有方法
  • 接口编号
  • Windows 10操作技巧:如何在 Windows 10 中恢复永久删除的文件
  • Mac数据恢复:Mac 十大数据恢复软件详细评测
  • iPad照片、联系人、笔记恢复工具: iPad 数据恢复软件
  • 2026 年预估适用于 Windows 10_11 的 10 款最佳数据恢复软件
  • 2025 年 9 款最佳 PDF 文档管理编辑工具
  • CF1736C2 Good Subarrays (Hard Version)
  • A Rock N Roll Fantasy
  • 从损坏_格式化_删除的源中提取数据的 7 款数据恢复软件
  • P12949 [GCJ Farewell Round #1] ASCII Art 题解
  • 高级专家/初阶架构师)的面试模拟
  • andriod集成x5内核
  • 为什么 VS Code 停止调试后 Python 进程还在?
  • Jenkins更换IP后,访问速度慢的问题解决.251103
  • Modbus协议地址模型详解学习笔记
  • 首次博客
  • CF2161 Pinely Round 5 (Div. 1 + Div. 2) 游记(VP)
  • 以太网交换技术
  • 2025-11-03 NOIP 模拟赛1 赛后总结
  • flex:1 什么意思