<分区>
案例 A:
list1=[0, 1, 2, 3]
list2=list1
list1=list1+[4]
print(list1)
print(list2)
输出:
[0, 1, 2, 3, 4]
[0, 1, 2, 3]
(这种非变异行为也会发生在连接多个条目的列表时,以及“乘以”列表时,例如 list1=list1*2
,实际上任何类型的“重新赋值”,它使用中缀运算符对列表执行操作,然后使用“=”将该操作的结果分配给相同的列表名称
在这种情况下,list1 指向的原始列表对象在内存中没有改变,list2 仍然指向它,只是在内存中为 list1 现在指向的连接结果创建了另一个对象(现在有内存中两个截然不同的列表对象)
案例 B:
list1=[0, 1, 2, 3]
list2=list1
list1.append(4)
print(list1)
print(list2)
---
输出:
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4]
案例 C:
list1=[0, 1, 2, 3]
list2=list1
list1[-1]="foo"
print(list1)
print(list2)
输出:
[0, 1, 2, 'foo']
[0, 1, 2, 'foo']
在 B 和 C 的情况下,list1 指向的原始列表对象发生了变化,list2 仍然指向同一个对象,因此 list2 的值发生了变化。 (内存中仍然只有一个列表对象,它已经发生了变异)。
这种行为对我这个菜鸟来说似乎不一致。这有充分的理由/效用吗?
编辑:
我将列表变量名称从“list”和“list_copy”更改为“list1”和“list2”,因为这显然是一个非常糟糕且令人困惑的名称选择。
我选择了 Kabanus 的回答,因为我喜欢他指出变异操作在 Python 中总是(?)显式的方式。
事实上,可以通过将 Kabanus 的回答总结为他的两个陈述来对我的问题做一个简短的回答:
-“在 python 中,变异操作是显式的”
-“加法[或乘法]运算符[在列表对象上执行]创建一个新对象,并且不会隐式更改 x[列表对象]。”
我还可以添加:
-“每次使用方括号描述列表时,都会创建一个新的列表对象”
[这是来自:http://www-inst.eecs.berkeley.edu/~selfpace/cs9honline/Q2/mutation.html ,关于这个主题的很好的解释]
在 Kabanus 的回答之后,我还意识到在跟踪程序中的突变时必须多么小心:
l=[1,2]
z=l
l+=[3]
z=z+[3]
和
l=[1,2]
z=l
z=z+[3]
l+=[3]
将产生完全不同的 z 值。这一定是一个常见的错误来源,不是吗?
我才刚刚开始学习,还没有深入研究 OOP 概念,但我想我已经开始理解围绕函数范式的大惊小怪是什么......