• python中浅拷贝和深度拷贝教程


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

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

    一、对象赋值

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

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

    二、浅拷贝

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    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]]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    浅拷贝(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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    可以看到 现在 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

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

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

    '''
    学习中遇到问题没人解答?小编创建了一个Python学习交流群:711312441
    寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
    '''
    In [16]:
    
    m[2].append(3)
    n[1]=5
    print(m)
    print(n)
    
    [1, 'a', ['a', 'b', 3]]
    [1, 5, ['a', 'b']]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

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

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

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

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

    四、深入解析

    1、b = a.copy(): 浅拷贝, a 和 b 是一个独立的对象,但他们的子对象还是指向统一对象(是引用)。
    在这里插入图片描述
    2、b = copy.deepcopy(a): 深度拷贝, a 和 b 完全拷贝了父对象及其子对象,两者是完全独立的。
    在这里插入图片描述

  • 相关阅读:
    不渴望得到,不害怕失去|佛系态度|无所谓,无欲无求 状态分析
    中间件
    自己在家给电脑重装系统Win10教程
    Linux底层基础知识
    【图形学】29 更复杂的光照
    6、云原生安全之falco的规则解读(部分)(下)
    视频监控系统/视频汇聚平台EasyCVR平台页面展示优化
    4.1 设计模式_单例模式
    一个Springboot配置顺序问题,让我直接回滚代码了
    2023-10-28 关于MICROPYTHON的OTA实现
  • 原文地址:https://blog.csdn.net/qdPython/article/details/127752661