kimber_kimber

导航

python--深拷贝和浅拷贝

先上例子

 1 def test_fun():
 2     a = [1, "hi", [2, 3], {"key": "123"}]
 3     b = copy.copy(a)
 4     c = copy.deepcopy(a)
 5     print('id(a)=',id(a))  
 6     print('id(b)=',id(b))
 7     print('id(c)=', id(c))
 8     a[2].append(4)
 9     a[0]=2
10     print('a=',a)
11     print('b=',b)
12     print('c=',c)

运行结果:

id(a)= 1638010289472
id(b)= 1638010288576
id(c)= 1638010289024
a= [2, 'hello', [2, 3, 4], {'key': '123'}]
b= [1, 'hello', [2, 3, 4], {'key': '123'}]
c= [1, 'hello', [2, 3], {'key': '123'}]

总结如下:

浅拷贝:

1.浅拷贝会创建一个新的容器对象

2.对于对象元素,浅拷贝只使用了原始元素的引用

深拷贝:

1.深拷贝会创建一个新的容器对象

2.对于对象的元素,深拷贝会重新生成一个对象

首先,我们看到例子中id(a) id(b) id(c) 为三个不同的值 ,是因为b,c 分别创建了新的容器 

其次,a[2]=[2,3] 这个列表元素发生了变化,但是 b[2] 仍然保持和a[2] 相同,c[2] 保持原来的值,就印证了上面 浅拷贝只是使用了原始元素的引用,也就是说他和a[2] 指向的是同一块内存

   而深拷贝是重新生成了一个对象

  我们可以用如下方法查看一下

    print('id(a[2])',id(a[2]))
    print('id(b[2])', id(b[2]))
    print('id(c[2])', id(c[2]))

输出结果:
id(a[2]) 2007144113600
id(b[2]) 2007144113600
id(c[2]) 2007144113408

  然后,我们给 a[0] =2,此时b[0],c[0] 元素值仍然等于1,这就引出了一个点:深拷贝和浅拷贝都是针对可变数据类型 

   python 有六大数据类型: 可变--list,dict,set    不可变--Number, String,Tuple

  而python 有一个对象缓存机制:

Python有一个缓存对象的机制,以便重复使用。例如当我们创建多个等于1的引用时,实际上是让所有这些引用指向同一个对象,以达到节省资源的目的  
python会对-5-256(包括256)的整型数据和短字符串进行缓存
而当我们把1改成2时,实际是开辟了一块新的缓存地址

我们同样可以用id()来查看a[0],b[0],c[0]  的地址,你会发现 只有a[0] 的地址发生了改变

    print('id(a[0])',id(a[0]))
    print('id(b[0])', id(b[0]))
    print('id(c[0])', id(c[0]))

运行结果:
改变前:
id(a[0]) 2878205028656
id(b[0]) 2878205028656
id(c[0]) 2878205028656
改变后:
id(a[0]) 2878205028720
id(b[0]) 2878205028656
id(c[0]) 2878205028656

1.深拷贝和浅拷贝的区别:有没有拷贝子对象

2.深拷贝和浅拷贝的使用场景 

  浅拷贝

  • 使用切片操作[:]
  • 使用工厂函数(如list/dict/set)
  • copy模块的copy()方法
def test_copy_fun3():
    l1=[1,[2,3],{'name':'lily'}]
    l2=list(l1) #list()属于浅拷贝
    l3=l1[0:3:1] #切片属于浅拷贝
    print('id(l1)=',id(l1))
    print('id(l2)=',id(l2))
    print('id(l3)=', id(l3))
    l1[1].append(4)
    print('l1=', l1)
    print('l2=', l2)
    print('l3=', l3)

运行结果:
id(l1)= 3012146690944
id(l2)= 3012095536384
id(l3)= 3012146690240
l1= [1, [2, 3, 4], {'name': 'lily'}]
l2= [1, [2, 3, 4], {'name': 'lily'}]
l3= [1, [2, 3, 4], {'name': 'lily'}]

3.赋值

  赋值和深拷贝,浅拷贝是有区别的,赋值语句并没有生成新的容器,看下面的例子

def test_fun():
    a = [1, "hello", [2, 3]]
    b = a
    print('\nid(a)=',id(a))  # 外面容器拷贝了,所以a和b的id不一样
    print('id(b)=',id(b))
    a[2].append(4)
    a[0]=2
    print('id(a[2])',id(a[2]))
    print('id(b[2])', id(b[2]))
    print('a=',a)
    print('b=',b)

运行结果
id(a)= 1524765088576
id(b)= 1524765088576
id(a[2]) 1524765094464
id(b[2]) 1524765094464
a= [2, 'hello', [2, 3, 4], {'key': '123'}]
b= [2, 'hello', [2, 3, 4], {'key': '123'}]

 

posted on 2021-03-04 13:22  kimber_kimber  阅读(33)  评论(0编辑  收藏  举报