为什么这个赋值语句不是单向的?

时间:2013-03-14 19:51:21

标签: python python-3.x

这个问题很容易理解,这是程序 -

hisc = [1,2,3,4]
print("\n", hisc)

ohisc = hisc
hisc.append(5)

print("\nPreviously...", ohisc)
print("\nAnd now...", hisc)
input("\nETE")

当我运行时,ohisc得到5.为什么ohisc会改变?如何阻止它改变? 如果这是明显的事情,请道歉。

3 个答案:

答案 0 :(得分:5)

Python variables are references。因此,赋值会复制引用而不是变量的内容。

为了避免这种情况,您所要做的就是创建一个 new 对象:

ohisc = list(hisc)

这是使用list constructor,它从给定的可迭代创建一个新列表。

或者,您也可以从切片(创建新对象)进行分配:

ohisc = hisc[:]

[]general slice operator,用于从给定集合中提取子集。我们简单地省略了开始和结束位置(它们分别默认为集合的开头和结尾)。

答案 1 :(得分:2)

你肯定需要了解Konrad Rudolph的答案中的所有内容。我认为在你的具体情况下,这也是你想要的。但通常有更好的方法:如果你避免变异对象(即,就地更改它们),那么两个名称是否指向同一个对象永远不会重要。例如,您可以更改此内容:

hisc.append(5)

到此:

hisc = hisc + [5]

这不会就地改变hisc;它会创建一个新的list,并在其末尾添加5,然后将其分配给hisc。因此,ohisc指向与list相同的hisc这一事实并不重要 - list仍未存在,ohisc指向。

假设你想用0替换列表中的所有负值。这很容易变异:

for i in range(len(lst)):
    list[i] = max(list[i], 0)

但没有更容易:

lst = [max(elem, 0) for elem in lst]

现在,如果你想删除每个否定列表元素怎么办?循环时序列的形状不能更改,因此您必须复制列表(这样您可以在更改另一个时循环复制一个副本),或者提出更复杂的算法(例如,向后交换每个0然后在结尾处移除所有0)。但这很容易做到不可变:

lst = [elem for elem in lst if elem >= 0]

那么,你什么时候想变异?好吧,通常你想要对同一个对象进行两次引用,所以当你更新一个时,另一个看到了这些变化。在这种情况下,您显然必须对另一个进行实际更改才能看到。

答案 2 :(得分:1)

这里有一个很好的解释:Python: copying a list the right way

基本上,你正在制作一个指向列表的指针,但你要做的是复制一份列表。

请改为尝试:

hisc = [1,2,3,4]
ohisc = hisc[:]