首页 问答 不可变数据类型和可变数据类型都可以多个引用指向同一个对象吗
问题详情
在 Python 中,无论是可变数据类型(如列表、字典)还是不可变数据类型(如整数、字符串、元组),多个变量引用指向同一个对象都是允许且常见的行为。
这是 Python 引用模型的核心特性:变量只是对象的标签(名字),而不是盒子。多个标签可以贴在同一个物体上。
Python 中的变量本质上是指向内存中对象的指针。当你执行b = a时,Python不会复制对象,而是让b也指向a所指向的那个对象。此时,该对象的“引用计数”加 1
对于可变对象(如list,dict,set),多个引用指向同一个对象时,修改其中一个变量,会影响所有指向该对象的变量
对于不可变对象(如int,str,tuple),多个引用指向同一个对象也是完全合法的。
区别在于:因为你不能修改不可变对象的内容,所以不会出现“改一个变全部”的副作用。如果你试图“修改”,实际上是创建了一个新对象,并将变量指向新对象,而其他变量依然指向旧对象。
# 不可变类型示例
str_a = "hello"
str_b = str_a  # str_b 和 str_a 指向同一个字符串对象
print(str_a is str_b)  # True (确实是同一个对象)
# 试图"修改" str_b (实际上是重新赋值)
str_b = str_b + " world" 
# 观察 str_a
print(str_a)  # 输出: "hello"      <-- str_a 没变
print(str_b)  # 输出: "hello world" <-- str_b 指向了新创建的对象
# 验证它们现在指向不同的对象
print(str_a is str_b)  # False

回答

在 Python 交互式命令行(REPL)中输入:
python


>>> a = 1000
>>> b = 1000
>>> a is b
False



在交互式模式(REPL)中,你输入的每一行虽然被视为独立的“代码块”编译,但它们都运行在同一个全局作用域(Global Scope)中。
第一行 a = 1000:在全局命名空间中创建了一个变量 a,指向一个值为 1000 的整数对象。
第二行 b = 1000:在全局命名空间中创建了一个变量 b。
第三行 a is b:Python 去全局命名空间找 a 和 b,它们都还在。
结论:变量不会因为一行代码执行结束就消失,除非你显式删除它(del a)或者程序退出。
为什么 a is b 是 False?(整数缓存机制)

这才是问题的关键。Python 为了优化性能,会对小整数进行缓存(Interning),但对大整数通常不会。
小整数缓存范围:通常是 [-5, 256]。在这个范围内的整数,无论在哪里创建,Python 都会复用同一个对象。
整数行为:对于超出这个范围的整数(如 1000),Python 默认每次遇到字面量 1000 时,都会创建一个新的整数对象(除非在同一个代码块内被优化器识别)。
在 REPL 中的具体情况:
由于 REPL 是逐行执行的,每一行都是一个独立的代码块:
  1. 第一行a = 1000
    • 编译器看到字面量1000
    • 创建一个整数对象Obj_1(值 1000)。
    • a指向Obj_1
    • 该行执行结束。
  2. 第二行b = 1000
    • 这是一个新的代码块。之前的优化上下文不复存在。
    • 编译器再次看到字面量1000
    • 创建另一个新的整数对象Obj_2(值 1000)。
    • b指向Obj_2
  3. 第三行a is b
    • 检查a(指向Obj_1) 和b(指向Obj_2) 是否是同一个对象。
    • 显然Obj_1不是Obj_2
    • 返回False

3. 对比:如果在脚本文件中运行

如果你把这三行写在一个.py文件里运行:
python

a = 1000 b = 1000 print(a is b)

在某些 Python 版本或编译器优化下,结果可能是True
原因:整个脚本(或同一个函数内)被视为一个代码块。编译器在进行常量折叠(Constant Folding)优化时,可能会发现代码块内有两个相同的常量1000,于是让它们指向同一个对象以节省内存。
但在 REPL 中,这种跨行的常量优化通常不会发生,因为每一行都是独立编译和执行的。

事实 1:变量 a 存储在全局命名空间中,只要不被覆盖或删除,它一直存在。
事实 2:1000 的对象没有被“丢弃”,a 依然紧紧引用着第一个 1000 对象。
事实 3:b 引用的是第二个新创建的 1000 对象。
真相:a is b 为 False 是因为 Python 没有缓存大整数,且 REPL 的逐行执行机制导致创建了两次对象,而不是因为对象被垃圾回收了。

版权:言论仅代表个人观点,不代表官方立场。转载请注明出处:https://www.stntk.com/question/2543.html

发表评论
暂无评论

还没有评论呢,快来抢沙发~

点击联系客服

在线时间:8:00-16:00

客服QQ

70068002

客服电话

400-888-8888

客服邮箱

70068002@qq.com

扫描二维码

关注微信公众号

扫描二维码

手机访问本站