Python:两个对象相同[重复]

ctzwtxfj  于 2023-01-01  发布在  Python
关注(0)|答案(6)|浏览(132)
    • 此问题在此处已有答案**:

10年前关闭了。

    • 可能重复:**

Assignment of objects and fundamental types

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上执行。再次问一下,为什么?我以前从未见过这样的事情发生。

ymzxtsji

ymzxtsji1#

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
kq4fsx7k

kq4fsx7k2#

当你执行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
wwtsj6pe

wwtsj6pe3#

它们实际上引用了同一个对象。
试试这个:

a = [1,2,3]
b = a
print b is a
b[0] = 0
print b is a

您将看到a和b都发生了更改,并且彼此仍然相同。

r8xiu3jd

r8xiu3jd4#

这段代码打印True。为什么?
因为...
仅当两个变量指向同一对象时,"is"才返回True
如果它们命名相同的对象。"指向"是一个粗俗的术语,暗指一个低得多的编程模型。
在这里它们是具有相同值的不同对象。
不,他们不是。
在Python中,b = a的意思是"b将不再是它当前命名的任何东西的名称,而成为a当前命名的任何东西的名称"。同一个对象,而不是副本。
在Python中,不会隐式地复制内容。
打印[3,2,1][3,2,1],似乎就解释器而言,它们是同一个对象
因为他们是。
并且在B上的操作将自动在A上执行。
因为它们是同一个物体。
再说一遍,为什么?
再说一遍,因为他们是。
...这就好像你想到了每一个明显的测试确认的行为,但拒绝拒绝拒绝拒绝你的核心假设,一旦每一个测试相矛盾,即使没有任何文献支持你的核心假设(因为事实上它是错误的)。
我以前从没见过这种事。
那么你以前肯定没有在Python中测试过类似的东西,因为Python中一直都是这样的,甚至在编程语言中也不是那么奇怪; Java对所有非基元类型的东西都做同样的事情,C#对类(引用类型)也做同样的事情,同时做你对结构(值类型)显然期望的事情,这就是所谓的"引用语义",这绝不是一个新的想法。

oymdgrw7

oymdgrw75#

我不确定列表的工作原理是否相同,但请看numpy.array()教程中关于浅拷贝和深拷贝的内容:http://www.scipy.org/Tentative_NumPy_Tutorial#head-1529ae93dd5d431ffe3a1001a4ab1a394e70a5f2
a = b只是创建了一个对同一对象的新引用。要获得一个真实的的副本,你可能会发现列表对象有一些类似于b = a.copy()链接中的深度复制示例的东西。然后你可以说有两个引用具有相同值的两个独立对象。
而且我认为大多数OO语言都是这样工作的,因为=只是创建一个新的引用,而不是一个新的对象。

tkqqtvp1

tkqqtvp16#

a = [1,2,3]
b = a
print b is a

您正在比较对同一个list的引用。如果执行以下操作:

a = [1,2,3]
b = [1,2,3]
print b is a

你应该得到一个假。

相关问题