鱼C论坛

 找回密码
 立即注册
查看: 32|回复: 6

序列id值的变化

[复制链接]
发表于 7 天前 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
在序列中,对于列表s的增量赋值,s*=2与s=s*2两种方式赋值导致系统中的存储位置不一致,为什么?
比如 s=[1,2,3,4],id(s)=2228157685440
以 s*=2增量赋值,id(s)=2228157685440
以s=s*2增量赋值,id(s)=2228138391424
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 7 天前 | 显示全部楼层
在 Python 中,s *= 2s = s * 2 对于列表的行为不同,根源在于列表是可变对象,而乘法运算符的处理方式有所区别。

  • s *= 2:这是原地操作(in-place),会调用列表的 __imul__ 方法。该方法直接在原列表上添加元素,然后返回原列表对象本身。因此,id(s) 保持不变,因为存储位置没有变。
  • s = s * 2:这是新建操作,先调用 __mul__ 方法,它会创建一个新的列表对象(包含原列表元素的重复),然后再将变量 s 指向这个新对象。所以 id(s) 会变化,因为存储位置发生了改变。


简单来说:s *= 2 是“修改自身”,内存不改;s = s * 2 是“生成新对象”,内存必改。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 7 天前 | 显示全部楼层
这个现象涉及到Python列表的可变对象特性:

s *= 2 是「原位修改」(in-place),直接扩展原列表,所以id不变;
s = s * 2 是「重新赋值」,先计算新对象(生成新列表),再绑定到变量s,所以id变化。

做个类比:前者是在原有容器里加水,后者是拿个新容器装原来的水再倒进去。本质上是因为 *= 运算符对可变对象做了优化,减少了内存分配的开销。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 7 天前 | 显示全部楼层
小派 发表于 2026-5-18 17:13
这个现象涉及到Python列表的可变对象特性:

s *= 2 是「原位修改」(in-place),直接扩展原列表,所以i ...

非常感谢,明白了
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 7 天前 | 显示全部楼层
小派 发表于 2026-5-18 17:13
这个现象涉及到Python列表的可变对象特性:

s *= 2 是「原位修改」(in-place),直接扩展原列表,所以i ...

非常感谢,明白了
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 4 天前 | 显示全部楼层
楼主能发现这个问题也很细心。我试了下,列表是你说的这种情况。可是换成普通的赋值,无论是哪种都会变
s=[1,2,3,4]
id(s)
2116399283392
s*=2
id(s)
2116399283392
a=3
id(a)
140734140929208
a*=3
id(a)
140734140929400
c=5
id(c)
140734140929272
c=c*2
id(c)
140734140929432
这又是为什么呢?@FishC
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 4 天前 | 显示全部楼层
我夏天的到来 发表于 2026-05-21 08:57
楼主能发现这个问题也很细心。我试了下,列表是你说的 ...


楼主观察得很仔细!这个现象背后是 Python 中**可变对象**与**不可变对象**的关键区别。

【原因解释】  

1. 列表是可变对象  
当你执行 s *= 2 时,Python 会调用列表的 __imul__ 方法,直接在原列表对象上修改内容(把自身元素重复一遍),因此 id 不变。  
  1. s = [1,2,3,4]
  2. id(s)  # 假设 2116399283392
  3. s *= 2
  4. id(s)  # 还是 2116399283392,同一个列表对象
复制代码


2. 整数是不可变对象  
整数一旦创建就不能修改。所以 a *= 3 等价于 a = a * 3 —— 都是先计算新值,然后用新值创建新整数对象,再让变量 a 指向这个新对象。旧的对象可能被回收,所以 id 必然改变。  
  1. a = 3
  2. id(a)  # 140734140929208
  3. a *= 3  # 实际是 a = a * 3,创建新整数 9,id 变 140734140929400
复制代码


3. 普通赋值也遵循同样规则  
c = c * 2 也是计算新值、创建新对象、将变量名绑定到新对象,所以 id 变了。这与 c *= 2 对不可变对象的效果完全一致。

【总结】  
- 对于**可变对象**(如列表、字典、集合),*= 一般会原地修改,id 不变。  
- 对于**不可变对象**(如整数、浮点数、字符串、元组),*= 等同于重新赋值,一定会产生新对象,id 改变。  

楼主能观察到这种差异,说明对 Python 对象模型已经有了很实在的理解了!继续加油~

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2026-5-25 00:13

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表