首页 新闻 会员 周边

不可变数据类型和可变数据类型都可以多个引用指向同一个对象吗

0
[已解决问题] 解决于 2026-03-13 09:35
在 Python 中,无论是可变数据类型(如列表、字典)还是不可变数据类型(如整数、字符串、元组),多个变量引用指向同一个对象都是允许且常见的行为。
这是 Python 引用模型的核心特性:变量只是对象的标签(名字),而不是盒子。 多个标签可以贴在同一个物体上。
Python 中的变量本质上是指向内存中对象的指针。当你执行 b = a 时,Python 不会复制对象,而是让 b 也指向 a 所指向的那个对象。此时,该对象的“引用计数”加 1
 
对于可变对象(如 listdictset),多个引用指向同一个对象时,修改其中一个变量,会影响所有指向该对象的变量
对于不可变对象(如 intstrtuple),多个引用指向同一个对象也是完全合法的。
区别在于:因为你不能修改不可变对象的内容,所以不会出现“改一个变全部”的副作用。如果你试图“修改”,实际上是创建了一个新对象,并将变量指向新对象,而其他变量依然指向旧对象。
# 不可变类型示例
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

 

 

 

*Tesla*的主页 *Tesla* | 小虾三级 | 园豆:1516
提问于:2026-03-13 09:32
< >
分享
最佳答案
0
在 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 的逐行执行机制导致创建了两次对象,而不是因为对象被垃圾回收了。

*Tesla* | 小虾三级 |园豆:1516 | 2026-03-13 09:35
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册