• Python 引用、浅拷贝、深拷贝解析


    1、=的作用。

    仅仅是地址的引用,当原列表或者新列表中任意元素改变,均会对另外一个产生影响

    # 引用
    # 本例中属于地址的引用,其中a和b共用同一块内存
    # 当修改共用内存中的任意的内容是时,均会影响到另外的内容
    a = [0, 1, 2, [3, 4]]
    b = a
    
    # 修改a[0]后,a[0]和b[0]都会改变
    a[0] = 10
    print("a:", a)
    print("b:", b)
    
    # 修改b[0]后,a[0]和b[0]都会改变
    b[0] = 0
    print("a:", a)
    print("b:", b)
    
    # 修改a[3][0]后,a[3][0]和b[3][0]都会改变
    a[3][0] = 30
    print("a:", a)
    print("b:", b)
    
    # 修改b[3][0]后,a[3][0]和b[3][0]都会改变
    b[3][0] = 3
    print("a:", a)
    print("b:", b)
    
    # 可以看到两个列表的内存地址相同
    print("列表a的内存地址是:", id(a))
    print("列表b的内存地址是:", id(b))
    View Code
     

    2、使用列表的copy()方法或者copy模块的copy()方法实现拷贝

    a = ["a0", "a1", "a2", ["a3", "a4"]]
    b = a.copy()
    # print("a:", a)
    # print("b:", b)
    print("a的内存地址是:", id(a))
    print("b的内存地址是:", id(b))
    View Code
     

    通过列表的copy()方法,可以得到一个与原列表相同的列表,当通过id()方法,查看两者的内存地址时,可以发现,两者的内存地址不同,可以当做将原列表拷贝了一份,而不是对于地址的引用。

    但是,当对a列表或者b列表的前三个元素进行修改时,可以观察到仅修改了一个列表内的元素,对于另外一个列表的元素没有影响。比如

    a[0] = 0
    b[1] = 1
    print(a) #[0, 'a1', 'a2', ['a3', 'a4']]
    print(b) #['a0', 1, 'a2', ['a3', 'a4']]

    可以看出,修改a[0]或者b[1]时均不会修改另一个列表的对应元素。然而有例外,看下面的例子

    print(a)  # ['a0', 'a1', 'a2', ['a3', 'a4']]
    print(b)  # ['a0', 'a1', 'a2', ['a3', 'a4']]
    a[3][0] = 3
    print(a)  # ['a0', 'a1', 'a2', [3, 'a4']]
    print(b)  # ['a0', 'a1', 'a2', [3, 'a4']]
    b[3][1] = 4
    print(a)  # ['a0', 'a1', 'a2', [3, 4]]
    print(b)  # ['a0', 'a1', 'a2', [3, 4]]

    当修改a[3][0]时,b[3][0]也会跟着改变,当使用id()函数查看a[3][0]和b[3][0]时发现两者的内存地址相同,可以认为b[3][0]并不是从a那里复制了一份,而是直接指向了a[3][0]的内存地址,这样就可以解释为什么修改a列表的的列表时会影响到其他的了。

    3、将所有的数据拷贝一份,需要使用copy模块的 deepcopy()方法

    import copy
    a = ["a0", "a1", "a2", ["a3", "a4"]]
    b = copy.deepcopy(a)

    使用deepcopy()方法实现列表的深拷贝,这种方式将原列表的元素拷贝一份,无论原列表内是否存在嵌套。

    print(a)  # ['a0', 'a1', 'a2', ['a3', 'a4']]
    print(b)  # ['a0', 'a1', 'a2', ['a3', 'a4']]
    a[3][0] = 3
    print(a)  # ['a0', 'a1', 'a2', [3, 'a4']]
    print(b)  # ['a0', 'a1', 'a2', ['a3', 'a4']]
    b[3][1] = 4
    print(a)  # ['a0', 'a1', 'a2', [3, 'a4']]
    print(b)  # ['a0', 'a1', 'a2', ['a3', 4]]

    修改内容时仅会改变自身,不会影响其他。

    总结:

    利用=的时候,仅仅是引用,而非拷贝,修改旧的或者新的都会影响另外一个,牵一发而动全身。

    使用列表的copy方法或者使用copy模块的copy()方法,仅仅开辟一块新的内存空间,将原列表的第一层元素复制一份新的,而列表内的嵌套不会复制,仅仅是引用了内层列表的地址,属于空有其表(因为内层的无论通过新列表还是旧列表都能修改)

    使用deepcoopy()方法拷贝列表,不仅开辟新空间,而且还将原列表的所有的元素都复制一份,无论原列表内是否存在嵌套的列表,属于形神具备(因为内层的列表元素不再是通过引用,而是真真正正的复制了一份新的)

    PS:对于数字和字符串,赋值、浅拷贝和深拷贝的值都指向同一个内存地址。

  • 相关阅读:
    HTTP、HTTP2
    1-1 用本地代码调试线上环境代码
    js判断触摸方向
    1-1 node 基础
    1-2 nodejs小节 文件读取
    c++ 递归斐波那契算法及时间复杂度
    十进制转换成二进制以 二进制转换成 8进制和16进制
    centos6.5 安装cmake 3.3.2
    回文字符串
    -Dmaven.multiModuleProjectDirectory system property is not set. Check $M2_HOME environment variable
  • 原文地址:https://www.cnblogs.com/June-King/p/10596210.html
Copyright © 2020-2023  润新知