首页 > 编程语言 >【学习笔记】Python深浅copy拷贝解析

【学习笔记】Python深浅copy拷贝解析

时间:2022-11-17 14:23:32浏览次数:70  
标签:内存地址 Python 元素 list1 列表 print 拷贝 copy id

一、列表的赋值(一般用于读操作)

  这个和列表的深浅拷贝其实没有关系,就是一个赋值操作;

  list1和list2指向的是同一片内存地址;

  即,你家有套房子,叫清华楼A栋101室,也叫清华楼A栋1层1室,名字不同,但是同一个房子。

 1 list1 = [
 2     "Jason",
 3     18,
 4     [1, 2]
 5 ]
 6 list2 = list1  # list1和list2指向的是同一个,改1个,另一个也会变
 7 print(list1)  # ['Jason', 18, [1, 2]]
 8 print(list2)  # ['Jason', 18, [1, 2]]
 9 print(id(list1))  # 2133190750464
10 print(id(list2))  # 2133190750464

 

 

二、列表的浅拷贝copy(一般用于写操作)

  如果只是读操作,没必要进行拷贝,浪费内存地址;

  浅拷贝copy,会在一片新的内存地址,创建一个新的列表,但是列表内的元素,不管该元素是可变类型,还是不可变类型,新列表的元素还是指向旧列表元素的内存地址;

  这样在进行写操作,即增删改时:

    如果列表的元素都是不可变类型,那么没什么问题,修改一个列表,是不影响另外一个列表的;

    如果列表的元素中有可变类型,那么,修改一个列表的可变类型中的元素时,另一个列表中的可变类型的元素也会被修改。

  浅拷贝copy就是,你家有套房子(list1),你又新买了套房子(list2),但还是你住,所以,房子里的人没有变化,列表里的元素也没有变化。

 1 list1 = [
 2     "Jason",
 3     18,
 4     [1, 2]
 5 ]
 6 list3 = list1.copy()
 7 print(id(list1))  # 2775467405632
 8 print(id(list3))  # 2775467374784
 9 print(id(list1[0]))  # 2775467372784
10 print(id(list3[0]))  # 2775467372784
11 print(id(list1[2]))  # 2775466065152
12 print(id(list3[2]))  # 2775466065152
13 list1[1] = 20
14 list1[2][0] = 333
15 print(list1)  # ['Jason', 20, [333, 2]]
16 print(list3)  # ['Jason', 18, [333, 2]]

  可以看到,在浅拷贝copy模式下,list3和list1的内存地址发生了改变,即,list3不是指向list1指向的内存地址,而是在新的内存地址创建了一个新的列表;

  但是,list3中的元素,不管是可变类型,还是不可变类型,都指向了list1中元素指向的内存地址,新瓶装旧酒;

  对于不可变类型元素,一个列表元素修改后,并不改变该元素的值,而是会在新的内存地址创建新的值,并和该列表的元素建立新的映射关系,并不会影响另一个列表元素和旧值的映射关系;

  list1[1]的修改并没有影响到list3[1];

  对于可变类型元素,一个列表元素修改后,会在该元素对应的旧内存地址中直接修改值,新、旧列表元素都没有建立新的映射关系,会影响另一个列表元素。

  所以,同时对不可变类型list1[1]和可变类型list1[2]中的元素list1[2][0]修改后,list3[1]不受影响,但list3[2]中的元素list2[2][0]被修改了。

 

 

三、列表的深拷贝copy(一般用于写操作)

  深拷贝copy,会在一片新的内存地址,创建一个新的列表,

  新列表内的元素,如果是不可变类型,新列表的元素还是指向旧列表元素的内存地址,如果是可变类型,则在新内存地址中创建新的元素拷贝;

  如果是可变类型嵌套,比如列表里的元素还是列表,同理;

  这样在进行写操作,即增删改时,修改一个列表的元素,是不会影响到另一个列表的元素的;

  针对可变类型的元素,深拷贝copy就是,你家有套房子(list1),你又新买了套房子(list4),你自己住房子list1,你双胞胎弟弟住房子list4。

 1 import copy
 2 
 3 list1 = [
 4     "Jason",
 5     18,
 6     [1, 2]
 7 ]
 8 list4 = copy.deepcopy(list1)
 9 print(id(list1))  # 1904758082112
10 print(id(list4))  # 1904758079744
11 print(id(list1[1]))  # 1904752421712
12 print(id(list4[1]))  # 1904752421712
13 print(id(list1[2]))  # 1904757785472
14 print(id(list4[2]))  # 1904758158336
15 list1[1] = 20
16 list1[2][0] = 333
17 print(list1)  # ['Jason', 20, [333, 2]]
18 print(list4)  # ['Jason', 18, [1, 2]]

  可以看到,深拷贝copy中,对于可变类型元素list1[2],list4[2]在新的内存地址中建立了新的元素拷贝;

  这样,在修改list1中的元素时,list2中的元素不受影响。

PS:参考资料:老男孩培训Egon老师视频 (https://www.bilibili.com/video/BV1QE41147hU) P96-P98

标签:内存地址,Python,元素,list1,列表,print,拷贝,copy,id
From: https://www.cnblogs.com/auto-s-info/p/16898543.html

相关文章

  • Python中报错Invalid return character or leading space in header: Cookie
    这个问题主要是读取的配置文件config.ini里该cookie参数遇到的空格问题主要是在配置文件里cookie_data=XXXXXXX参数值后面有个莫名其妙的空格可能产生的原因是:在从页......
  • python的异常捕获
    trytry:有可能会出错的代码(try会去监测代码执行是否出错)except:当try里面的代码执行出现错误时,会执行except中的代码,可以在这里对异常进行处理else:try中的代码执......
  • python简短代码技巧
      #1.两个字典的合并x={'a':1,'b':2}y={'c':3,'d':4}x.update(y)print(x)#字典的合并dct1={'name':'wjh','age':20}dct2={'city':'beijing'......
  • python 的逻辑判断
    与shell的逻辑判断不同,python的逻辑判断不需要加结束符号,但是需要在判断条件后加“:”号例:ifage_of_Bob==guess_age:其他的逻辑判断用法差不多,像if....else,if.........
  • DE 算法的变体python实现
    上演化计算课的时候老师讲了一种DE算法的改进算法CoDE,于是看了下CoDE的论文中的算法步骤:算法中使用的三种交叉策略:根据不同的交叉策略采取不同的变异策略:超参数的三......
  • python - 初识python
    python2中文需要加字符编码样例:#-*-coding:utf-8-*-python3不需要加python变量引用用括号例子:name="你好,世界"print(name)%s变量字符串%d变量字符数字打......
  • 使用python中的requests库调用接口上传文件
    importrequestsurl="https://192.168.4.103/iof/base/resource/addResourceBf"payload={'resoId':'reso_fenlei16568654548266IP134232246455','resoName':'12......
  • Python删除文件多种方法详解!
    在开发过程中,创建文件之后当我们不需要这个文件或者创建错了就需要删除该文件,那么Python中删除文件的方法有几种?使用Python删除文件有多种方法,本文为大家介绍几种常用......
  • vb中filecopy拷贝文件
    FileCopy("源文件名","目标文件名")两个参数都是必选的,且都包含路径。在VB中filecopy函数可以直接调用。而CopyFile函数则不能要先定义......
  • python神经网络编程2之用python搭建神经网络
    【python基础】环境:JupyterNotebookforninrange(10):print(n)pass#标志循环结束,下一行回正常缩进,done只打印一次我也可以删掉orzprint("done") ......