Python标签
res = []
def func(obj):
    res.append(obj)
a = [1, 2, 3]
print(id(a))        # 2897774181960
func(a)
print(id(res[0]))   # 2409845052424
print("res: ", res)
a.append(4)
print("res: ", res)
res:  [[1, 2, 3]]
res:  [[1, 2, 3, 4]]从输出可以看到,a和res[0]的id一样,说明指向了同一块内存空间,所以a改变了之后res[0]也跟着改变了,你以为拷贝了,其实并没有
原因:
Python没有变量,我们平时所说的变量其实只是标签,是引用。
执行:values=[0,1,2]的时候,python做的事情是首先创建一个列表对象[0,1,2],然后给它贴上名为values的标签。如果随后执行values=[3,4,5]的话,python做的事情是创建另一个列表对象[3,4,5],然后把刚才那张名为values的标签从前面的[0,1,2]对象上撕下来,重新贴到[3,4,5]这个对象上。
所以,这里的a和res[0]就相当于两张标签贴到了同一个对象[1,2,3]上
浅拷贝
解决办法是用拷贝,这里先说浅拷贝shallow copy
注意:[:]生成对象的拷贝或者是复制序列,不再是引用和共享变量,但此法只能顶层复制
res = []
def func(obj):
    res.append(obj[:])  # 这里不一样
a = [1, 2, 3]
print(id(a))        # 1558831191048
func(a)
print(id(res[0]))   # 1558832493512
print("res: ", res)
a.append(4)
print("a: ", a)
print("res: ", res)
res:  [[1, 2, 3]]
a:  [1, 2, 3, 4]
res:  [[1, 2, 3]]可以看到a和res[0]的id不一样了,a改变了之后,res[0]没有改变,对于这种场景,浅拷贝就适用了,但如果包含子对象,浅拷贝就有问题了
a = [0, [1, 2], 3]
b = a[:]
a[0] = 8
a[1][1] = 9
print(a)  # [8, [1, 9], 3]
print(b)  # [0, [1, 9], 3]可以看到,b[1][1]也跟着改变了,这就是浅拷贝只做顶层拷贝的效果
 
原因从图里就可以看出来了,a[1]和b[1]还是指向了同一个对象
深拷贝
解决办法使用深拷贝
import copy
a = [0, [1, 2], 3]
b = copy.deepcopy(a)
print(id(a[1]))  # 2071720571784
print(id(b[1]))  # 2071721298184
a[0] = 8
a[1][1] = 9
print(a)  # [8, [1, 9], 3]
print(b)  # [0, [1, 2], 3]深拷贝之后就指向两个完全不同的对象了
对象也是一样
import copy
class Person:
    def __init__(self):
        self.num = [1, 2]
p1 = Person()
print(p1.num)   # [1, 2]
p2 = p1         # 指向同一个内存
print(p2.num)   # [1, 2]
p3 = copy.deepcopy(p1)  # 深拷贝
print(p3.num)   # [1, 2]
p1.num.append(3)
print(p1.num)   # [1, 2, 3]
print(p2.num)   # [1, 2, 3] 也改变了
print(p3.num)   # [1, 2] 没有改变 
                     
                        
                        