a = [1,2,3]
b = a
print b is a
此代码打印True。为什么?如果两个变量指向同一个对象,则“is”仅返回True,在这种情况下,它们是具有相同值的不同对象。 “==”将返回True,但“is”不应返回。
但是,因为
b.reverse()
print a,b
打印[3,2,1] [3,2,1],似乎就解释器而言,它们是同一个对象,而b上的操作将自动在a上执行。再次,为什么?我以前从未见过这样的事情。
答案 0 :(得分:13)
a = [81, 82, 83]
b = a
print(a is b) #prints True
这就是实际发生的事情:
以及类似的内容:
a = [81,82,83]
b = [81,82,83]
print(a is b) # False
print(a == b) #True, as == only checks value equality
In [24]: import sys
In [25]: a=[1,2,3]
In [26]: sys.getrefcount(a) #number of references to [1,2,3] are 2
Out[26]: 2
In [27]: b=a #now b also points to [1,2,3]
In [28]: sys.getrefcount(a) # reference to [1,2,3] got increased by 1,
# as b now also points to [1,2,3]
Out[28]: 3
In [29]: id(a)
Out[29]: 158656524 #both have the same id(), that's why "b is a" is True
In [30]: id(b)
Out[30]: 158656524
何时使用copy
模块:
In [1]: a=[1,2,3]
In [2]: b=a
In [3]: id(a),id(b)
Out[3]: (143186380, 143186380) #both point to the same object
In [4]: b=a[:] #now use slicing, it is equivalent to b=copy.copy(a)
# or b= list(a)
In [5]: id(a),id(b)
Out[5]: (143186380, 143185260) #as expected both now point to different objects
# so now changing one will not affect other
In [6]: a=[[1,2],[3,4]] #list of lists
In [7]: b=a[:] #use slicing
In [8]: id(a),id(b) #now both point to different object as expected
# But what about the internal lists?
Out[8]: (143184492, 143186380)
In [11]: [(id(x),id(y)) for (x,y) in zip(a,b)] #so internal list are still same objects
#so doing a[0][3]=5, will changes b[0] too
Out[11]: [(143185036, 143185036), (143167244, 143167244)]
In [12]: from copy import deepcopy #to fix that use deepcopy
In [13]: b=deepcopy(a)
In [14]: [(id(x),id(y)) for (x,y) in zip(a,b)] #now internal lists are different too
Out[14]: [(143185036, 143167052), (143167244, 143166924)]
了解更多详情:
In [32]: def func():
....: a=[1,2,3]
....: b=a
....:
....:
In [34]: import dis
In [35]: dis.dis(func)
2 0 LOAD_CONST 1 (1)
3 LOAD_CONST 2 (2)
6 LOAD_CONST 3 (3)
9 BUILD_LIST 3
12 STORE_FAST 0 (a) #now 'a' poits to [1,2,3]
3 15 LOAD_FAST 0 (a) #load the object referenced by a
18 STORE_FAST 1 (b) #store the object returned by a to b
21 LOAD_CONST 0 (None)
24 RETURN_VALUE
In [36]: def func1():
....: a=[1,2,3]
....: b=[1,2,3]
....:
....:
In [37]: dis.dis(func1) #here both a and b are loaded separately
2 0 LOAD_CONST 1 (1)
3 LOAD_CONST 2 (2)
6 LOAD_CONST 3 (3)
9 BUILD_LIST 3
12 STORE_FAST 0 (a)
3 15 LOAD_CONST 1 (1)
18 LOAD_CONST 2 (2)
21 LOAD_CONST 3 (3)
24 BUILD_LIST 3
27 STORE_FAST 1 (b)
30 LOAD_CONST 0 (None)
33 RETURN_VALUE
答案 1 :(得分:5)
执行a = [1, 2, 3]
时,您将名称a
绑定到列表对象。当您执行b = a
时,您将名称b
绑定到任何a
- 在这种情况下是列表对象。因此,它们是相同的...一个对象可以有多个名称。值得阅读Python Data Model。
如果你想制作listobj的副本,那么你可以看b = a[:]
使用slice创建浅拷贝,或copy.copy
使用浅拷贝(应该适用于任意对象)或奇怪的是copy.deepcopy
- 一份深刻的副本。
你还会注意到CPython中有一些令人惊讶的东西,它会缓存短字符串/小整数......
>>> a = 4534534
>>> b = a
>>> a is b
True
>>> b = 4534534
>>> a is b
False
>>> a = 1
>>> b = a
>>> a is b
True
>>> b = 1
>>> a is b
True
答案 2 :(得分:1)
它们实际上引用了同一个对象。
试试这个:
a = [1,2,3]
b = a
print b is a
b[0] = 0
print b is a
你会看到a和b都被改变了,并且彼此仍然相同。
答案 3 :(得分:1)
我不确定列表的工作方式是否相同,但是从numpy.array()教程中了解浅层和深层副本:http://www.scipy.org/Tentative_NumPy_Tutorial#head-1529ae93dd5d431ffe3a1001a4ab1a394e70a5f2
a = b
只是创建对同一对象的新引用。要获得真实副本,您可能会发现列表对象与链接中的深层复制示例类似,因此b = a.copy()
。然后你可以说有两个具有相同值的独立对象的引用。
另外我认为大多数OO语言的工作方式都是这样的=
只是创建一个新的引用,而不是新的对象。
答案 4 :(得分:1)
此代码打印True。为什么?
因为b is a
。
“is”仅在两个变量指向同一对象
时才返回True
如果他们为同一个对象命名。 “指向”是粗俗的术语,暗示了低级别的编程模型。
在这种情况下,它们是具有相同值的不同对象。
不,他们不是。
在Python中,b = a
表示“b
将不再是其当前名称的名称(如果有的话),并成为任何a
当前名称的名称”。同一个对象。不是副本。
事情不会在Python中隐式复制。
打印[3,2,1] [3,2,1],似乎就解释器而言,它们是同一个对象
因为他们是。
将自动在a上执行b上的操作。
因为它们是同一个物体。
再次,为什么?
再次,因为他们是。
......就好像你想到了确认行为的每一个明显的测试,但是一旦每个测试都与之相矛盾,拒绝拒绝你的核心假设,即使文献中没有任何内容支持你的核心假设(因为事实上它是假的。
我以前从未见过这样的事情。
然后你必须在Python之前从未测试过这样的东西,因为它总是以这种方式在Python中运行。在编程语言中甚至不是那么奇怪; Java对于不是原始类型的所有内容都做同样的事情,而C#对类(引用类型)执行相同的操作,同时执行您对结构(值类型)的期望。它被称为“参考语义”,它绝不是一个新的想法。
答案 5 :(得分:0)
a = [1,2,3]
b = a
print b is a
您正在比较对同一list
的引用。如果您执行以下操作:
a = [1,2,3]
b = [1,2,3]
print b is a
你应该得到一个假的。