zoukankan      html  css  js  c++  java
  • python的深浅拷贝

    深浅拷贝

    学习深浅拷贝,需要先了解一下列表在内存中的存储方式

    1. 列表在内存中存储方式

    1.1 创建列表

    lst = ['ymn', 'xcy', [9, 99]]
    

    列表在内存中实际上存放的并不是一个,一个的值, 列表在内存中存放的是索引和对应值的内存地址

    所以我们通过列表的索引取值, 实际上是通过索引取到对应的值的地址

    2. 列表的引用

    2.1 创建列表并引用

    lst = ['ymn', 'xcy', [9, 99]]
    lst1 = lst
    print(id(lst)) # 1442941688264
    print(id(lst1))# 1442941688264
    

    这里在堆区并没有重新开辟空间存放新的值, 我们通过画图来看一下在内存中发生的事情.

    lst 和 lst1 都是指向同一个地址, 如果lst1的值发生改变, lst也是随之改变的

    3. 浅拷贝

    浅拷贝: 可变和不可变元素都是直接拷贝地址, 两个列表可能会黏在一起.

    3.1 创建列表并浅拷贝

    lst = ['ymn', 'xcy', [9, 99]]
    lst2 = lst.copy()
    
    print(id(lst)) # 1442941688264
    print(id(lst2))# 1758475685768
    
    print(id(lst[0]))  # 1309438439403
    print(id(lst2[0])) # 1309438439403
    
    print(id(lst[2]))  # 1309438999999
    print(id(lst2[2])) # 1309438999999
    

    同样我们也是通过画图来观察浅拷贝会在内存中发生什么变化

    从图中我们可以看出, 在内存中只是把之前原列表的每个元素的内存copy了一份放在了一个新的列表中, 你可以理解成换了瓶子(列表),并没有换酒(元素),还是指向原来的那些值。

    3.2 修改原列表

    3.2.1 修改不可变的元素

    lst = ['ymn', 'xcy', [9, 99]]
    lst2 = lst.copy()
    
    lst[0] = 'YMN'
    print(lst)   # ['YMN', 'xcy', [9, 99]]
    print(lst2)  # ['ymn', 'xcy', [9, 99]]
    

    当我们通过索引修改原列表的第一个值时,会在内存中开辟一个新的空间存放至,然后原列表会断掉之前索引和地址指向,并将索引指向新的地址 。又因为浅拷贝的列表中的地址是和原列表的一样,所以他的地址还是原来的地址并没有发生改变所以还是原来的值。

    3.2.2 修改可变元素

    lst = ['ymn', 'xcy', [9, 99]]
    lst2 = lst.copy()
    
    lst[2][1] = 999
    print(lst)   # ['ymn', 'xcy', [9, 999]]
    print(lst2)  # ['ymn', 'xcy', [9, 999]]
    

    因为这次修改的是可变元素里面的值, 由于浅拷贝的列表指向的地址和原来一样,再加上是对元素的元素修改,索引浅拷贝的列表的索引指向的地址并没有发生改变,但是这个元素的内部发生了改变,所以原列表和浅拷贝的列表都会发生改变。

    4. 深拷贝

    深拷贝: 不可变元素还是直接拷贝地址, 不可变元素创建一个新的地址存放, 两个列表完全隔离.

    4.1 创建列表并进行深拷贝

    import copy
    lst = ['ymn', 'xcy', [9, 99]]
    lst3 = copy.deepcopy(lst)
    
    print(id(lst))  # 1234292221819
    print(id(lst3)) # 1234292676878
    
    print(id(lst[1]))  # 1442922218416
    print(id(lst3[1])) # 1442922218416
    
    print(id(lst[2]))    # 2777233030152
    print(id(lst3[2]))   # 2777215797064
    

    通过id我们也可以发现,深拷贝会把可变和不可变数据进行区分,不可变的直接把地址copy一份,而可变的则是

    重新开辟空间,分配新的地址。

    4.2 修改原列表

    首先修改不可变的元素我们就不介绍了,这个在内存中发生的变化是和浅拷贝一样的。

    4.2.1 修改可变元素

    import copy
    lst = ['ymn', 'xcy', [9, 99]]
    lst3 = copy.deepcopy(lst)
    
    lst[2][1] = 999
    print(lst)   # ['ymn', 'xcy', [9, 999]]
    print(lst2)  # ['ymn', 'xcy', [9, 99]]
    

    因为这次可变元素是重新在内存中创建的,所以当原列表的可变元素的值发生变化,并不影响新的列表,新的列表的索引仍然对应着原来的地址,指向原来的值。

    5. 总结

    浅拷贝和深拷贝的本质区别就是对待可变元素,一个是直接copy地址,一个是新创建一个地址.

    一个不完全隔离, 一个完全隔离.

  • 相关阅读:
    宽屏手机显示9.png的图片拉伸不均衡
    android中 System.exit(0)的理解
    android 由于界面控件过多耗时处理办法
    iOS开发笔记--sqlite3 语句总结
    iOS开发笔记--iOS应用架构谈
    iOS开发笔记--iOS 学习资料整理
    iOS开发笔记--iOS、mac开源项目及库汇总
    iOS开发笔记--iphone练习之手势识别(双击、捏、旋转、拖动、划动、长按)UITapGestureRecognize
    iOS开发笔记--Masonry介绍与使用实践:快速上手Autolayout
    iOS开发笔记--使用CocoaPods来管理iOS项目的依赖库
  • 原文地址:https://www.cnblogs.com/xcymn/p/13524979.html
Copyright © 2011-2022 走看看