• 深浅拷贝


    一、示例

    import copy
    
    a = [11, 22]
    b = a
    print(id(a))  # 17812744
    print(id(b))  # 17812744
    c = copy.deepcopy(a)
    print(id(a))  # 17812744
    print(id(c))  # 17810952
    print(a)  # [11, 22]
    print(c)  # [11, 22]
    a.append(33)
    print(a)  # [11, 22, 33]
    print(c)  # [11, 22]

    可以看到a、b内存地址是一样,可如下图表示;而c是完完全全拷贝了一份a指向的内容,这就是深拷贝。

    二、深浅拷贝

    浅拷贝:copy.copy()

    import copy
    
    a = [11, 22]
    b = [33, 44]
    c = [a, b]
    d = copy.copy(c)
    print(id(c))  # 17811464
    print(id(d))  # 17405960
    a.append(55)
    print(c)  # [[11, 22, 55], [33, 44]]
    print(d)  # [[11, 22, 55], [33, 44]]

    把c里的东西取出来,然后d指向它,大致如下图所示。

    深拷贝:copy.deepcopy()

    import copy
    
    a = [11, 22]
    b = [33, 44]
    c = [a, b]
    d = copy.deepcopy(c)
    print(id(c))  # 17942536
    print(id(d))  # 17943112
    a.append(55)
    print(c)  # [[11, 22, 55], [33, 44]]
    print(d)  # [[11, 22], [33, 44]]

    深拷贝:我已经完完全全拷贝过来了,你改你的东西,不关我事。

    三、其他

    import copy
    
    a = [11, 22]
    b = [33, 44]
    c = [a, b]
    d = copy.copy(c)
    e = copy.deepcopy(c)
    print(id(c))  # 17680392
    print(id(d))  # 17275144
    print(id(e))  # 17681736
    c.append([55, 66])
    print(c)  # [[11, 22], [33, 44], [55, 66]]
    print(d)  # [[11, 22], [33, 44]]
    print(e)  # [[11, 22], [33, 44]]

    深拷贝、浅拷贝:往c里添加数据,不关我事。

    四、坑

    如果copy.copy()拷贝的是元祖,那么不会进行浅拷贝。因为元祖是不可变类型,意味着数据一定不能修改,因此用copy.copy()的时候会自动判断,如果拷贝的是元祖,仅仅是指向这个元祖。

    import copy
    
    a = [11, 22]
    b = copy.copy(a)
    print(id(a))  # 17878344
    print(id(b))  # 17471496
    a = (11, 22)
    b = copy.copy(a)
    print(id(a))  # 17454856
    print(id(b))  # 17454856
    c = a
    print(id(c))  # 17454856

    对于上面这种情况,copy.deepcopy()同理。但是,请看下面代码:

    import copy
    
    a = [11, 22]
    b = [33, 44]
    c = (a, b)
    d = copy.copy(c)
    print(id(c))  # 12080904
    print(id(d))  # 12080904
    e = copy.deepcopy(c)
    print(id(c))  # 12080904
    print(id(e))  # 12095880
    print(c)  # ([11, 22], [33, 44])
    print(e)  # ([11, 22], [33, 44])
    a.append(55)
    print(c)  # ([11, 22, 55], [33, 44])
    print(e)  # ([11, 22], [33, 44])

    所以, 如果用copy.cpoy()、copy.deepcopy()对一个全部都是不可变类型的数据进行拷贝,那么它们的结果相同,都是指向;如果拷贝的是一个拥有不可变类型的数据,即使元祖是最顶层,那么copy.cpoy()依然是指向,而copy.deepcopy()这时则是深拷贝了。

    五、切片也是浅拷贝

    a = [11, 22]
    b = [33, 44]
    c = [a, b]
    d = c[:]
    print(id(c))  # 17750024
    print(id(d))  # 17751752
    print(id(c[0]))  # 17751688
    print(id(d[0]))  # 17751688
    print(a)  # [11, 22]
    a.append(55)
    print(c)  # [[11, 22, 55], [33, 44]]
    print(d)  # [[11, 22, 55], [33, 44]]

    d=c[:]d=copy.copy(c) 一样,属于浅拷贝。 

    六、字典的copy()方法

    d = {"name": "pd", "age": 18}
    c = d.copy()
    print(id(d))  # 6662152
    print(id(c))  # 6662280
    # 验证
    d = {"name": "pd", "age": 18, "xx": [11, 22]}
    c = d.copy()
    d["xx"].append(33)
    print(d)  # {'age': 18, 'xx': [11, 22, 33], 'name': 'pd'}
    print(c)  # {'age': 18, 'xx': [11, 22, 33], 'name': 'pd'}
    # 这说明了,使用字典copy()方法的时候,字典里指向的value是共享的。

    七、应用

    import copy
    
    a = [11, 22]
    
    def func(a):
        a.append(33)
    
    func(a)
    print(a)  # [11, 22, 33]
    
    func(copy.deepcopy(a))
    print(a)  # [11, 22, 33]
    """
    打印发现没有再次添加33,说明了copy.deepcopy(a)把a复制了一份,
    将复制的新列表传入函数内,对其进行操作,而没有影响到函数外的a
    """
    func(a)
    print(a)  # [11, 22, 33, 33]

    你想拷贝列表、字典、元祖、对象等等,想拷贝什么就拷贝什么,关键在于,你想干什么?比如你从网上好不容易爬取到了某些数据,忘了保存,就进行测试了。如果你使用了深拷贝的话,这样在测试时即使污染了数据,也不会对源数据产生影响。

  • 相关阅读:
    opengl像素格式管理
    opengl的体系结构
    符号文件——Windows 应用程序调试必备
    [Study Note] Patterns in Practice 20100404
    “在我的机器上可以运行”症状自查(Windows编程)
    [Study Note] Patterns in Practice 20100402
    [Study Note] Patterns in Practice 20100406
    [Study Note] Design and Testability 20100410
    [Study Note] Patterns in Practice 20100403
    [Study Note] Design and Testability 20100411
  • 原文地址:https://www.cnblogs.com/believepd/p/10410019.html
Copyright © 2020-2023  润新知