zoukankan      html  css  js  c++  java
  • 『Python基础』第20节:深浅copy

    一. 赋值运算

    l1 = [1, 2, 'conan', [11, 22]]
    l2 = l1
    
    l1[0] = 111
    print(l1)  # [111, 2, 'conan', [11, 22]]
    print(l2)  # [111, 2, 'conan', [11, 22]]
    print(id(l1[0]))  # 1872924208
    print(id(l2[0]))  # 1872924208
    
    l1.append(333)
    print(l1)  # [111, 2, 'conan', [11, 22], 333]
    print(l2)  # [111, 2, 'conan', [11, 22], 333]
    print(id(l1))  # 2211423993544
    print(id(l2))  # 2211423993544
    
    l1[3].append(666)
    print(l1)  # [111, 2, 'conan', [11, 22, 666], 333]
    print(l2)  # [111, 2, 'conan', [11, 22, 666], 333]
    print(id(l1[3]))  # 2211453800136
    print(id(l2[3]))  # 2211453800136
    

    ​ 从上面的运行结果可以看到, 对于赋值运算来说, l1与l2指向的是同一个内存地址, 所以它们是完全一样的. 其中一个变量对列表进行改变, 剩下的变量在使用列表时, 就是使用的改变之后的列表.

    赋值运算

    二. 浅copy

    # 同一代码块下
    l1 = [1, 2, 'conan', [11, 22]]
    l2 = l1.copy()
    
    l1[0] = 111
    print(l1)  # [111, 2, 'conan', [11, 22]]
    print(l2)  # [1, 2, 'conan', [11, 22]]
    print(id(l1[0]))  # 1872924208
    print(id(l2[0]))  # 1872920688
    
    print(id(l1[1]))  # 1872920720
    print(id(l2[1]))  # 1872920720
    
    l1.append(333)
    print(l1)  # [111, 2, 'conan', [11, 22], 333]
    print(l2)  # [1, 2, 'conan', [11, 22]]
    print(id(l1))  # 2343138115272
    print(id(l2))  # 2343138954824
    
    l1[3].append(666)
    print(l1)  # [111, 2, 'conan', [11, 22, 666], 333]
    print(l2)  # [1, 2, 'conan', [11, 22, 666]]
    print(id(l1[3]))  # 2343138954952
    print(id(l2[3]))  # 2343138954952
    
    # 不同代码块下
    l1 = [1, 2, 'conan', [11, 22]]
    l2 = l1.copy()
    
    l1[0] = 111
    print(l1)  # [111, 2, 'conan', [11, 22]]
    print(l2)  # [1, 2, 'conan', [11, 22]]
    print(id(l1[0]))  # 1872924208
    print(id(l2[0]))  # 1872920688
    
    print(id(l1[1]))  # 1872920720
    print(id(l2[1]))  # 1872920720
    
    l1.append(333)
    print(l1)  # [111, 2, 'conan', [11, 22], 333]
    print(l2)  # [1, 2, 'conan', [11, 22]]
    print(id(l1))  # 2402040017736
    print(id(l2))  # 2402040018120
    
    l1[3].append(666)
    print(l1)  # [111, 2, 'conan', [11, 22, 666], 333]
    print(l2)  # [1, 2, 'conan', [11, 22, 666]]
    print(id(l1[3]))  # 2402040003848
    print(id(l2[3]))  # 2402040003848
    

    对于浅copy来说, 只是在内存中重新开辟了一个空间存放一个新列表, 但是新列表里面的元素与原列表里面的元素的内存地址是同一个. 所以, l1与l2的id不同, 但是里面内容的id是相同的.

    注意

    我们发现, 在更改l1的第一个元素, 也就是把 1 改为 111 之后, 内存地址是不一样的, 这是因为int类型是不可变的数据类型; 而列表时可变的数据类型, 当里面的列表增加一个元素后, 其内存地址是不变的.

    浅copy

    三. 深copy

    依旧是先看下代码

    import copy
    l1 = [1, 2, 'conan', [11, 22]]
    l2 = copy.deepcopy(l1)
    
    l1[0] = 111
    print(l1)  # [111, 2, 'conan', [11, 22]]
    print(l2)  # [1, 2, 'conan', [11, 22]]
    print(id(l1[0]))  # 1872924208
    print(id(l2[0]))  # 1872920688
    
    print(id(l1[1]))  # 1872920720
    print(id(l2[1]))  # 1872920720
    
    l1.append(333)
    print(l1)  # [111, 2, 'conan', [11, 22], 333]
    print(l2)  # [1, 2, 'conan', [11, 22]]
    print(id(l1))  # 2698658605000
    print(id(l2))  # 2698660016776
    
    l1[3].append(666)
    print(l1)  # [111, 2, 'conan', [11, 22, 666], 333]
    print(l2)  # [1, 2, 'conan', [11, 22]]
    print(id(l1[3]))  # 2698659950152
    print(id(l2[3]))  # 2698660016712
    

    对于深copy来说, 深copy后的列表是在内存中重新创建的. 而且Python为了节省内存以及提高性能, 它做了这么一件事:

    在深copy后的列表中,

    如果其元素是可变的数据类型就再重新创建一个;

    如果其元素是不可变的数据类型, 就公用一个, 也就是其内存地址是一样的.

    在上面代码中的运行结果也能看出来.

    深copy

    四. 总结

    浅copy: 嵌套的可变的数据类型 是 同一个.

    深copy: 嵌套的可变的数据类型 不是 同一个.

    五. 练习

    5.1 练习1

    写出下面代码的运行结果

    l1 = [1, 2, 3, ['conan']]
    l2 = l1[::]
    l1[-1].append(666)
    print(l1)
    print(l2)
    

    l1: [1, 2, 3, ['conan', 666]]

    l2: [1, 2, 3, ['conan', 666]]

    通过打印其id可以发现, l2 = l1[::] 的操作其实与浅copy一样.

  • 相关阅读:
    安卓小助手
    位图切割器&位图裁剪器
    OAuth2.0 的简介
    多账户的统一登录方案
    常用的一些SQL语句
    SQL语句的优化
    SpringCloud简介与5大常用组件
    数据库为什么需要锁机制?有哪些锁机制?
    高并发下如何优化能避免服务器压力过大?
    Spring MVC 简介
  • 原文地址:https://www.cnblogs.com/lpgit/p/11348662.html
Copyright © 2011-2022 走看看