zoukankan      html  css  js  c++  java
  • 深浅copy,何为深浅copy,深copy和浅copy两者有何不同

    copy,拷贝,顾名思义,自然是把东西复制过来,呈现在眼前的是一样的,例如:

    a = [1,2,3,4,5]
    b = a
    b.append(6)
    print(a,b)

     输出:

    [1, 2, 3, 4, 5, 6] [1, 2, 3, 4, 5, 6]

    很明显,a和b的值是一样的。因为对于赋值运算来讲,a与b指向的是同一内存地址,所以他们完全是一样的

    浅copy:

    a = [1,2,3,4,[5]]
    b = copy.copy(a)
    b[4].append(6)
    print(a)
    print(b)
    
    print(id(a))
    print(id(b))
    
    print(id(a[0]))
    print(id(b[0]))
    
    print(id(a[4]))
    print(id(b[4]))

    输出:

    [1, 2, 3, 4, [5, 6]]
    [1, 2, 3, 4, [5, 6]]
    3123924048968
    3123924049032
    140709039403264
    140709039403264
    3123924285128
    3123924285128

    可以看到,a和b的输出地址不一样,原因是对于浅copy来说,只是在内存中重新创建了开辟了一个空间存放一个新列表,但是新列表中的元素与原列表中的元素是公用的,且元素原地址一样不变。

    但我们如果对它进行增删改,两者是否会相互改变呢?

    从上面看,列表当中的可变数据类型进行增加元素时,两者是会相互影响的,且地址一直一致;

    但从下面看,对列表当中的不可变数据类型进行修改时,虽然元素地址一样,但两者是不会相互影响,并且经过修改后,元素地址发生改变,两者地址变得不一样。

    import copy
    a = [1,2,3,4,[5]]
    b = copy.copy(a)
    b[0] = 0
    print(a)
    print(b)
    print(id(a[0])) print(id(b[0]))

    输出:

    [1, 2, 3, 4, [5]]
    [0, 2, 3, 4, [5]]
    140709362168064
    140709362168032

    而在整个列表添加新的元素时,两者同样不会相互影响,只要copy过来的元素不发生改变,元素地址会一直保持一致

    import copy
    a = [1,2,3,4,[5]]
    b = copy.copy(a)
    b.append(8)
    
    print(a)
    print(b)
    
    print(id(a[0]))
    print(id(b[0]))

     输出:

    [1, 2, 3, 4, [5]]
    [1, 2, 3, 4, [5], 8]
    140709362168064
    140709362168064

    所以得出结论是,浅copy时,内存会开辟一个新的空间存放一个新的列表,所以地址不一致。列表中的元素和元素地址都会被copy过来,而可变数据类型(列表中的列表,二级列表)被当作一个整体不被拷贝,所以地址永远一致,对可变数据类型中的元素改变时,a和b会相互影响,元素永远相同。

    而一级列表中的不可变数据类型,虽然元素与地址都被复制过来,但两者进行修改时不会相互影响,并且修改后地址会变得不一致。而在一级列表添加新的元素时,两者同样不会相互影响,只要不改变copy过来的元素,地址会一直与copy过来的一致。

    深copy:

    import copy
    a = [1,2,3,4,[5]]
    b = copy.deepcopy(a)
    b[4].append(6)
    print(a)
    print(b)
    
    print(id(a))
    print(id(b))
    
    print(id(a[0]))
    print(id(b[0]))
    
    print(id(a[4]))
    print(id(b[4]))

    输出:

    [1, 2, 3, 4, [5]]
    [1, 2, 3, 4, [5, 6]]
    1861657304264
    1861657304328
    140709043532032
    140709043532032
    1861657540168
    1861657304456

    它是拷贝所有内容。包括内部(列表的列表)的所有,形成一个新的对象,虽然与之前的值和内容一模一样,但是它们时完完全全的两个对象,所以不仅a和b的地址不同,可变数据类型的地址同样被拿出来存在新的内存当中,地址同样会不一样,所以做出改变时不会相互影响;其它与浅copy一致,不可变数据类型改变时不会相互影响,且改变后地址会发生改变;

    注:

    当切片进行赋值时,两者地址会不一样,并且进行增删改时,两者互不影响:

    a = [1,2,3,4,5]
    b = a[0::]
    b.pop(0)
    print(a)
    print(b)
    print(id(a))
    print(id(b))

    输出:

    [1, 2, 3, 4, 5]
    [2, 3, 4, 5]
    2525473650376
    2525473414152

    仅存在一种情况,两者相互影响且地址永远一致:

    a = [1,2,3,4,5]
    b = a
    b.append(6)
    a.pop(2)
    print(a)
    print(b)
    print(id(a))
    print(id(b))

    输出:

    [1, 2, 4, 5, 6]
    [1, 2, 4, 5, 6]
    2957431125704
    2957431125704

    以上测试基于python3.7.4

  • 相关阅读:
    vscode添加python文件头模板
    解决Win平台VSCode中Python在控制台输出中文乱码的问题
    Windows系统解决VSCode终端无法输入问题
    python中pip安装包出现Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None))…………或无法pip install packname安装依赖包
    GET和POST的本质区别
    文件名排序
    乱码加密解密
    jQuery.validator 自定义验证消息
    Oracle查询某个表被那些存储过程引用
    note4
  • 原文地址:https://www.cnblogs.com/aizhinong/p/11336879.html
Copyright © 2011-2022 走看看