zoukankan      html  css  js  c++  java
  • python疑难问题---6、python中浅拷贝和深度拷贝

    python疑难问题---6、python中浅拷贝和深度拷贝

    一、总结

    一句话总结:

    浅拷贝(copy.copy()):拷贝父对象,不会拷贝对象的内部的子对象,也就是子对象共用
    深拷贝(copy.deepcopy()):完全拷贝父对象跟子对象,复制的对象和原来的对象互不相关
    import copy
    
    l = [1, 2, ['a', 'b']]
    s_copy = l.copy()  # 浅拷贝
    d_copy = copy.deepcopy(l)  # 深拷贝
    l.append(3)
    l[2].append('c')
    
    print(l)  # [1, 2, ['a', 'b', 'c'], 3]
    print(s_copy)  # [1, 2, ['a', 'b', 'c']]
    print(d_copy)  # [1, 2, ['a', 'b']]

    二、python中浅拷贝和深度拷贝

    博客对应课程的视频位置:6、python中浅拷贝和深度拷贝

    https://www.fanrenyi.com/video/32/307

    浅拷贝和深拷贝在面试和日常的开发中都会经常遇到

    我们就从 对象赋值、浅拷贝、深拷贝 三个方面来讲

    一、对象赋值

    In [1]:
    list1 = [1, 2, ['a', 'b']]
    list2 = list1
    print(list1)
    print(list2)
    
    [1, 2, ['a', 'b']]
    [1, 2, ['a', 'b']]
    
    In [2]:
    list1[0] = 3
    print(list1)
    print(list2)
    
    [3, 2, ['a', 'b']]
    [3, 2, ['a', 'b']]
    
    In [3]:
    list2[1]=[1,2]
    print(list1)
    print(list2)
    
    [3, [1, 2], ['a', 'b']]
    [3, [1, 2], ['a', 'b']]
    
    In [4]:
    print(id(list1))
    print(id(list2))
    
    1742901832264
    1742901832264
    

    结论:直接对象赋值,两个对象的地址是一样的,也就是这两个变量指向是同一个对象,两个变量会同步变化

    二、浅拷贝

    In [5]:
    import copy
    A = [1, 'a', ['a', 'b']]
    # B = A.copy() # 浅拷贝
    B = copy.copy(A) # 浅拷贝
    
    print(A)
    print(B)
    print(id(A))
    print(id(B))
    
    [1, 'a', ['a', 'b']]
    [1, 'a', ['a', 'b']]
    1742901926344
    1742901925512
    

    两个对象的内存地址不一样,也就是不是同一个对象

    In [6]:
    # 循环分别打印每个对象中的成员的地址
    # 打印A
    for i in A:
        print("值 {} 的地址是:{}".format(i,id(i)))
    
    值 1 的地址是:140724000563600
    值 a 的地址是:1742860054320
    值 ['a', 'b'] 的地址是:1742901889800
    
    In [7]:
    # 循环分别打印每个对象中的成员的地址
    # 打印B
    for i in B:
        print("值 {} 的地址是:{}".format(i,id(i)))
    
    值 1 的地址是:140724000563600
    值 a 的地址是:1742860054320
    值 ['a', 'b'] 的地址是:1742901889800
    

    int类型的1和字符串型的a都是不可变数据类型,不可变数据类型值一样,地址一样,值不一样,地址就不一样

    列表['a', 'b']是可变数据类型,可变数据类型是 变量中数据变的时候,地址不会变,值相同的两个对象,地址是不一样的,如果地址一样,表示指的是同一个对象

    现在 A[2] 和 B[2] 指向的是同一个地址,说明是同一个列表,一个改变,另外的一个也会同步改变

    通常来讲不可变元素包含:

    int,float,complex,long,str,unicode,tuple

    In [8]:
    # 在 A[2] 中增加元素
    A[2].append(3)
    print(A)
    print(B)
    
    [1, 'a', ['a', 'b', 3]]
    [1, 'a', ['a', 'b', 3]]
    
    In [9]:
    # 向A中增加元素
    A.append(3)
    print(A)
    print(B)
    
    [1, 'a', ['a', 'b', 3], 3]
    [1, 'a', ['a', 'b', 3]]
    
    In [10]:
    A[0]=2
    print(A)
    print(B)
    
    [2, 'a', ['a', 'b', 3], 3]
    [1, 'a', ['a', 'b', 3]]
    
    浅拷贝(copy.copy()):拷贝父对象,不会拷贝对象的内部的子对象,也就是子对象共用
    如果子对象是不可变数据类型,那么复制的对象和原来的对象互不影响
    如果是可变数据类型,那么复制的对象和原来的对象共用
     
    In [11]:
    A[2]=[1,2]
    print(A)
    print(B)
    
    [2, 'a', [1, 2], 3]
    [1, 'a', ['a', 'b', 3]]
    
    In [12]:
    print(id(A[2]))
    print(id(B[2]))
    
    1742901889416
    1742901889800
    

    可以看到 现在 A[2] 和 B[2] 的地址不一样了,那么他们就互不影响了

    其实看两个可变数据类型是否互相影响,就是看他们的地址是否一样

    三、深拷贝

    In [13]:
    m = [1, 'a', ['a', 'b']]
    n = copy.deepcopy(m)
    print(m)
    print(n)
    print(id(m))
    print(id(n))
    
    [1, 'a', ['a', 'b']]
    [1, 'a', ['a', 'b']]
    1742900283720
    1742900260680
    
    In [14]:
    # 循环分别打印每个对象中的成员的地址
    # 打印m
    for i in m:
        print("值 {} 的地址是:{}".format(i,id(i)))
    
    值 1 的地址是:140724000563600
    值 a 的地址是:1742860054320
    值 ['a', 'b'] 的地址是:1742900341320
    
    In [15]:
    # 循环分别打印每个对象中的成员的地址
    # 打印n
    for i in n:
        print("值 {} 的地址是:{}".format(i,id(i)))
    
    值 1 的地址是:140724000563600
    值 a 的地址是:1742860054320
    值 ['a', 'b'] 的地址是:1742900283208
    

    可以看到,m和n两个对象本身的地址是不一样的,

    并且m和n中成员中的可变数据类型的地址也是不一样的,所以它们两个是完全互不影响的

    In [16]:
    m[2].append(3)
    n[1]=5
    print(m)
    print(n)
    
    [1, 'a', ['a', 'b', 3]]
    [1, 5, ['a', 'b']]
    

    浅拷贝(copy.copy()):拷贝父对象,不会拷贝对象的内部的子对象,也就是子对象共用

      如果子对象是不可变数据类型,那么复制的对象和原来的对象互不影响

      如果是可变数据类型,那么复制的对象和原来的对象共用

    深拷贝(copy.deepcopy()):完全拷贝父对象跟子对象,复制的对象和原来的对象互不相关

    四、深入解析

    1、b = a.copy(): 浅拷贝, a 和 b 是一个独立的对象,但他们的子对象还是指向统一对象(是引用)。

    2、b = copy.deepcopy(a): 深度拷贝, a 和 b 完全拷贝了父对象及其子对象,两者是完全独立的。

     
     
  • 相关阅读:
    deepin linux手工更新系统
    redis使用redis-cli查看所有的keys及清空所有的数据
    使用浏览器地址栏调用CXF Webservice的写法
    windows 80端口被占用
    How to install 64-bit Google Chrome 28+ on 64-bit RHEL/CentOS 6 or 7
    CAS 单点登录流程
    Restful是什么,SOAP Webservice和RESTful Webservice
    SpringMVC中的@PathVariable
    VMWare安装苹果操作系统OS X
    eclipse(adt-bundle)的Android SDK Manager下载不了谷歌的东西怎么办?
  • 原文地址:https://www.cnblogs.com/Renyi-Fan/p/13222704.html
Copyright © 2011-2022 走看看