Python列表别名与相互引用递归行为的原理困惑
核心前提:列表是可变对象,传递的是引用
Python里的列表属于可变对象,当你把列表赋值给变量、或者用append()添加到另一个列表时,并没有复制列表本身,只是把指向这个列表的引用存了进去。也就是说,多个变量/列表元素可以指向同一个列表对象,修改其中一处,所有指向它的地方都会同步变化——这就是你提到的“别名”机制。
逐行拆解代码执行过程
我们一步步拆解你的代码运行逻辑:
1. 初始化列表
a = [1,2,3] b = [4,5]
此时内存里存在两个独立的列表对象:
- 变量
a指向列表[1,2,3] - 变量
b指向列表[4,5]
2. 将b追加到a中
a.append(b)
这一步是把b指向的列表引用添加到a的末尾,此时a的结构变为[1,2,3, <指向b的引用>],也就是说a[3]和b指向同一个列表对象[4,5]。
执行print(a[3][1])时,a[3]就是b对应的列表,取索引1的元素为5,因此输出5。
3. 将a追加到b中
b.append(a)
同样,这一步是把a的引用添加到b的末尾,此时b的结构变为[4,5, <指向a的引用>],即b[2]和a指向同一个列表对象[1,2,3, <指向b的引用>]。
执行print(b[2][1])时,b[2]就是a对应的列表,取索引1的元素为2,因此输出2。
4. 修改a[3][1]的值
a[3][1] = 6
因为a[3]和b指向同一个列表,修改a[3][1]等同于修改b[1],此时b对应的列表变为[4,6, <指向a的引用>],同时a[3]的内容也同步更新为[4,6, <指向a的引用>]。
5. 验证引用关系
print(a[3][2] is a)
a[3]是b对应的列表,a[3][2]是这个列表的第三个元素——也就是之前追加的a的引用,它和a指向同一个对象,is用于判断对象身份,因此结果为True。
print(b[2][3][2] == a)
逐层拆解:
b[2]是a对应的列表b[2][3]是a的第四个元素,即b对应的列表b[2][3][2]是b的第三个元素,即a的引用
b[2][3][2]和a指向同一个对象,==判断内容相等,因此结果为True。
循环引用的原理
当你把b追加到a、再把a追加到b后,就形成了循环引用:
a中包含指向b的引用b中包含指向a的引用
Python尝试打印a或b时,会陷入无限递归:打印a需要打印a[3](即b),打印b又需要打印b[2](即a),因此Python用[...]表示这种循环引用,避免无限输出,于是出现了你看到的[1, 2, 3, [4, 6, [...]]]和[4, 6, [1, 2, 3, [...]]]。
内容的提问来源于stack exchange,提问作者Johnyy

