我对Python中的pass-by-ref和pass-by-value感到困惑。
在下面的代码中,当listB = listA
时,listB应该被赋予ListA变量中列表的指针(引用)。对listB的任何更改都应该反映在listA上。但是,在我的测试中并非如此。我做错了代码吗?我正在运行Python 3.4.3
>>> listA = [1,2,3]
>>> listB = listA
>>> listA = [4,5,6]
>>> print(listA, listB)
[4, 5, 6] [1, 2, 3]
>>> listB[0] ='new'
>>> print(listA, listB)
[4, 5, 6] ['new', 2, 3]
答案 0 :(得分:2)
您完全重新分配listA
,因此它与listB
之间没有任何关系。
例如:
listA = [2,2,3]
listB = listA
id(listA)
Out[6]: 90404936
id(listB)
Out[7]: 90404936
listA[0]=2
id(listA)
Out[9]: 90404936
listB
Out[10]: [2, 2, 3]
但是当你重新分配listA
时,你会丢失id
:
listA = [3,3,3]
id(listA)
Out[12]: 92762056
但是listB
保持相同的ID:
id(listB)
Out[13]: 90404936
答案 1 :(得分:1)
执行listA = [4,5,6]
后,listA
(已分配给listB
)的引用不再指向listA
,因为您已完全替换listA
新名单。
如果删除该行,您会发现它按预期工作。
答案 2 :(得分:1)
你说:
我对python中的pass-by-ref和pass-by-value感到困惑。
实际上,Python不使用 按值调用或按引用调用:它使用call-by-object-sharing。这基本上就像按值调用,除了"值"问题实际上是对包含实际值的对象的引用。
从根本上说,在Python中考虑变量的方法是它们实际上是names that can refer to other objects,而不是自己的值。
答案 3 :(得分:0)
对于Python,将名称空间视为由列出名称和地址的2列表实现。另请注意,赋值运算符=
会导致右侧被计算,如果尚未表示,则在内存中表示,然后会导致赋值左侧的变量被绑定在符号表中到表示的地址。一次完成一行代码:
listA = [2, 3, 4]
导致2,3和4在特定地址的内存中表示。然后括号使列表对象在内存中表示,包含类的地址,int的长度以及元素的地址数组。最后,名称listA
放在名称空间表中,并绑定到该列表对象的地址。
listB = listA
第二个条目listB
在命名空间表中生成,并绑定到列表的相同地址。
listA = [4, 5, 6]
在内存中创建三个整数和一个列表的表示,并更改命名空间表中listA引用的地址,并将其绑定到新列表。
listB[0] = 'new'
导致字符串' new'要在内存中表示,然后更改绑定到listB
的列表对象,以便该列表的第一个元素现在引用该字符串的地址。
如果listA
没有被重新分配给新对象,它仍会指向同一个列表,您会在列表的第一个元素中看到相同的更改是否使用{{ 1}}或listA
令牌。