
在python中,所有数据都是对象。每个对象在内存中都有一个唯一的标识符(id),可以通过内置的 id() 函数获取。理解对象的“可变性”(mutable)和“不可变性”(immutable)是理解python中变量赋值和对象引用的关键。
让我们通过 id() 函数来验证这一点:
# 初始化一个字符串并打印其ID
some_str = "Hello"
print("变量值:", some_str)
print("变量ID:", id(some_str))
print("-" * 20)
# 修改字符串并再次打印其ID
some_str += " World" # 看起来是修改,实则创建新对象
print("变量值:", some_str)
print("变量ID:", id(some_str))
print("-" * 20)输出:
立即学习“Python免费学习笔记(深入)”;
变量值: Hello 变量ID: 4457023280 -------------------- 变量值: Hello World 变量ID: 4458388464 --------------------
从输出可以看出,当字符串 some_str 被“修改”后,它的内存ID发生了变化,这证实了字符串的不可变性:原对象未被修改,而是创建了一个新对象。
# 初始化一个列表并打印其ID
some_list = ["Hello"]
print("变量值:", some_list)
print("变量ID:", id(some_list))
print("-" * 20)
# 修改列表并再次打印其ID
some_list.append("World") # 直接在原对象上修改
print("变量值:", some_list)
print("变量ID:", id(some_list))
print("-" * 20)输出:
立即学习“Python免费学习笔记(深入)”;
变量值: ['Hello'] 变量ID: 4484419200 -------------------- 变量值: ['Hello', 'World'] 变量ID: 4484419200 --------------------
与字符串不同,列表 some_list 在被修改后,其内存ID保持不变。这证明了列表是可变数据类型,其内容可以在不改变对象本身内存地址的情况下进行修改。
在Python中,变量并不直接存储值,而是存储对内存中对象的引用(可以理解为指向对象的“指针”)。当一个变量被赋值给另一个变量,或者一个对象被添加到另一个数据结构中时,复制的不是对象的值,而是其引用。这意味着多个变量或数据结构中的元素可能指向同一个内存中的对象。这种现象被称为“别名”(Aliasing)。
# 初始化一个字符串和列表
some_str = "Hello"
print("some_str 值:", some_str, "ID:", id(some_str))
print("-" * 10)
some_list_1 = ["Hello"]
print("some_list_1 值:", some_list_1, "ID:", id(some_list_1))
print("-" * 10)
# 创建一个新列表,并追加上述两个变量
some_list_2 = []
some_list_2.append(some_str) # some_list_2[0] 存储 some_str 的引用
some_list_2.append(some_list_1) # some_list_2[1] 存储 some_list_1 的引用
print("some_list_2 的第一个元素:", some_list_2[0], "ID:", id(some_list_2[0]))
print("ID of some_list_2[0] == ID of some_str?:", id(some_list_2[0]) == id(some_str))
print("*" * 10)
print("some_list_2 的第二个元素:", some_list_2[1], "ID:", id(some_list_2[1]))
print("ID of some_list_2[1] == ID of some_list_1?:", id(some_list_2[1]) == id(some_list_1))
print("*" * 10)
# 修改原始的 some_str 和 some_list_1
some_str += " World" # some_str 指向新对象
print("修改后 some_str ID:", id(some_str))
some_list_1.append("World") # some_list_1 在原地址修改
print("修改后 some_list_1 ID:", id(some_list_1))
print("-" * 20)
# 再次检查 some_list_2 中的元素
print("some_list_2 的第一个元素:", some_list_2[0], "ID:", id(some_list_2[0]))
print("ID of some_list_2[0] == ID of some_str?:", id(some_list_2[0]) == id(some_str)) # False,因为some_str现在指向新对象
print("*" * 10)
print("some_list_2 的第二个元素:", some_list_2[1], "ID:", id(some_list_2[1]))
print("ID of some_list_2[1] == ID of some_list_1?:", id(some_list_2[1]) == id(some_list_1)) # True,因为some_list_1在原地址修改
print("*" * 10)输出:
立即学习“Python免费学习笔记(深入)”;
some_str 值: Hello ID: 4321089264 ---------- some_list_1 值: ['Hello'] ID: 4322442880 ---------- some_list_2 的第一个元素: Hello ID: 4321089264 ID of some_list_2[0] == ID of some_str?: True ********** some_list_2 的第二个元素: ['Hello'] ID: 4322442880 ID of some_list_2[1] == ID of some_list_1?: True ********** 修改后 some_str ID: 4322509360 修改后 some_list_1 ID: 4322442880 -------------------- some_list_2 的第一个元素: Hello ID: 4321089264 ID of some_list_2[0] == ID of some_str?: False ********** some_list_2 的第二个元素: ['Hello', 'World'] ID: 4322442880 ID of some_list_2[1] == ID of some_list_1?: True **********
这个实验清晰地展示了:
现在,我们将上述概念应用于一个更复杂的场景:列表相互引用,从而形成递归结构。
考虑以下代码片段:
a = [1,2,3] b = [4,5] a.append(b) # 1. 将列表 b 的引用追加到列表 a 中 print(a) # 此时 a 是 [1, 2, 3, [4, 5]]。a[3] 指向 b 所指向的同一个列表对象。 print(a[3][1]) # 访问 a[3] (即 b) 的第二个元素 b.append(a) # 2. 将列表 a 的引用追加到列表 b 中 print(b) # 此时 b 是 [4, 5, [1, 2, 3, [...]]]。b[2] 指向 a 所指向的同一个列表对象。 # 并且由于 a 已经包含了 b 的引用,b 现在又包含了 a 的引用,形成了循环引用。 print(b[2][1]) # 访问 b[2] (即 a) 的第二个元素 a[3][1] = 6 # 3. 修改 a[3] (即 b) 的第二个元素 print(a) print(b) # 由于 a[3] 和 b 指向同一个对象,修改 a[3][1] 等同于修改 b[1]。 print(a[3][2] is a) # 4. 检查 a[3][2] 是否就是对象 a print(b[2][3][2] == a) # 5. 检查 b[2][3][2] 的值是否等于 a 的值
输出:
立即学习“Python免费学习笔记(深入)”;
[1, 2, 3, [4, 5]] 5 [4, 5, [1, 2, 3, [...]]] 2 [1, 2, 3, [4, 6, [...]]] [4, 6, [1, 2, 3, [...]]] True True
掌握这些核心概念对于编写健壮、可预测的Python代码至关重要,尤其是在处理复杂数据结构时。如果需要避免别名引起的意外修改,可以考虑使用浅拷贝(list.copy() 或 copy.copy())或深拷贝(copy.deepcopy())来创建对象的独立副本。
以上就是Python对象引用、可变性与列表递归行为深度解析的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号