博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python学习之路7——深浅拷贝剖析
阅读量:5942 次
发布时间:2019-06-19

本文共 5139 字,大约阅读时间需要 17 分钟。

 一、对象赋值

  创建列表变量Alex,变量包含子列表,通过变量Alex给变量lzl赋值。

  然后对变量Alex的元素进行修改,此时lzl会有什么变化呢?让我们通过内存地址分析两者的变化。

1 #   对象赋值 2 import copy                     #import调用copy模块 3   4 Alex = ["Alex", 28, ["Python", "C#", "JavaScript"]] 5 lzl = Alex                       #直接赋值 6   7 #   修改前打印 8 print(id(Alex))              #打印列表在内存中的地址 9 print(Alex)                        #打印列表内容10 print([id(adr) for adr in Alex])   #打印列表中每个元素(包括子列表)在内存中的地址11 # 输出:  731666412 #        ['Alex', 28, ['Python', 'C#', 'JavaScript']]13 #        [2775776, 1398430400, 7318024]14 print(id(lzl))15 print(lzl)16 print([id(adr) for adr in lzl])17 # 输出:  731666418 #        ['Alex', 28, ['Python', 'C#', 'JavaScript']]19 #        [2775776, 1398430400, 7318024]20  21 #    对变量进行修改22 Alex[0]='Mr.Wu'23 Alex[2].append('CSS')24 print(id(Alex))25 print(Alex)26 print([id(adr) for adr in Alex])27 # 输出:  731666428 #        ['Mr.Wu', 28, ['Python', 'C#', 'JavaScript', 'CSS']]29 #        [5170528, 1398430400, 7318024]30 print(id(lzl))31 print(lzl)32 print([id(adr) for adr in lzl])33 # 输出:  731666434 #        ['Mr.Wu', 28, ['Python', 'C#', 'JavaScript', 'CSS']]35 #        [5170528, 1398430400, 7318024]

 通过上面的代码做出如下两图并进行分析:

  1、首先,创建了一个名为Alex的变量,这个变量指向一个list列表,从第一张图中可以看到列表中元素的地址(每次运行,结果可能不同)。

  然后通过变量Alex给变量lzl进行赋值,变量lzl指向Alex指向的内存地址(7316664)。

  Python中,对象的赋值都是进行对象引用(内存地址)的传递,被赋值的变量并没有开辟新内存,两个变量共用一个内存地址。

       2、第二张图中,由于Alex和lzl指向同一个对象(内存地址),所以对Alex的任何修改都会体现在lzl上。

  这里需要注意的一点是,str是不可变类型,所以当修改元素Alex为Mr.Wu时,内存地址由2775776变为了5170528。

  list是可变类型,元素['Python', 'C#', 'JavaScript', 'CSS']修改完后,内存地址仍然是7318024,没有发生改变。

---------------------------------------------------------------------------------------

  二、浅拷贝

  创建列表变量Alex,变量包含子列表,通过copy模块的浅拷贝函数copy()对变量Alex进行拷贝。

1 #   浅拷贝 2 import copy                     #import调用copy模块 3   4 Alex = ["Alex", 28, ["Python", "C#", "JavaScript"]] 5 lzl = copy.copy(Alex)                       #通过copy模块里面的浅拷贝函数copy() 6   7 #   修改前打印 8 print(id(Alex)) 9 print(Alex)10 print([id(adr) for adr in Alex])11 # 输出:  1046247212 #        ['Alex', 28, ['Python', 'C#', 'JavaScript']]13 #        [5462752, 1359960768, 10463232]14 print(id(lzl))15 print(lzl)16 print([id(adr) for adr in lzl])17 # 输出:  1020184818 #        ['Alex', 28, ['Python', 'C#', 'JavaScript']]19 #        [5462752, 1359960768, 10463232]20  21 #    对变量进行修改22 Alex[0]='Mr.Wu'23 Alex[2].append('CSS')24 print(id(Alex))25 print(Alex)26 print([id(adr) for adr in Alex])27 # 输出:  1046247228 #        ['Mr.Wu', 28, ['Python', 'C#', 'JavaScript', 'CSS']]29 #        [10151264, 1359960768, 10463232]30 print(id(lzl))31 print(lzl)32 print([id(adr) for adr in lzl])33 # 输出:  1020184834 #        ['Alex', 28, ['Python', 'C#', 'JavaScript', 'CSS']]35 #        [5462752, 1359960768, 10463232]

  通过上面的代码做出如下两图并进行分析:

  1、依然使用一个Alex变量,指向一个list类型的对象,list包含一个子list

        2、然后,通过copy模块里面的浅拷贝函数copy(),对Alex指向的对象进行浅拷贝,然后浅拷贝生成的新对象赋值给lzl变量。

  注意此时变量lzl新建了一块内存(10201848),此内存记录了list中元素的地址,对于list中的元素,浅拷贝就会使用原始元素的引用(内存地址)。

      3、当对Alex进行修改的时候,由于list中第一个元素“Alex”(str)为不可变类型,所以进行修改的后,第一个元素对应的地址变为了10151264。

  由于list中第三个元素['Python', 'C#', 'JavaScript'](list)为可变类型,修改后地址没有变化。所以最后变量lzl和变量Alex只是第一个元素不一样。

 

-----------------------------------------------------------------------------------------

  注:当我们使用下面的操作的时候,会产生浅拷贝的效果:

  • 使用切片[:]操作
  • 使用工厂函数(如list/dir/set)
  • 使用copy模块中的copy()函数

三、深拷贝

  创建列表变量Alex,变量包含子列表,通过copy模块的深拷贝函数deepcopy()对变量Alex进行拷贝。

1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 #-Author-Lian 4 #   深拷贝 5 import copy                     #import调用copy模块 6   7 Alex = ["Alex", 28, ["Python", "C#", "JavaScript"]] 8 lzl = copy.deepcopy(Alex)                       #通过copy模块里面的深拷贝函数deepcopy() 9  10 #   修改前打印11 print(id(Alex))12 print(Alex)13 print([id(adr) for adr in Alex])14 # 输出:  620271215 #        ['Alex', 28, ['Python', 'C#', 'JavaScript']]16 #        [4086496, 1363237568, 6203472]17 print(id(lzl))18 print(lzl)19 print([id(adr) for adr in lzl])20 # 输出:  620303221 #        ['Alex', 28, ['Python', 'C#', 'JavaScript']]22 #        [4086496, 1363237568, 6203512]23  24 #    对变量进行修改25 Alex[0]='Mr.Wu'26 Alex[2].append('CSS')27 print(id(Alex))28 print(Alex)29 print([id(adr) for adr in Alex])30 # 输出:  620271231 #        ['Mr.Wu', 28, ['Python', 'C#', 'JavaScript', 'CSS']]32 #        [5236064, 1363237568, 6203472]33 print(id(lzl))34 print(lzl)35 print([id(adr) for adr in lzl])36 # 输出:  620303237 #        ['Alex', 28, ['Python', 'C#', 'JavaScript']]38 #        [4086496, 1363237568, 6203512]

通过上面深拷贝的代码做出如下两图并进行分析:

     1、依然使用一个Alex变量,指向一个list类型的对象,list包含一个子list。

        2、然后,通过copy模块里面的深拷贝函数deepcopy(),对Alex指向的对象进行深拷贝,然后深拷贝生成的新对象赋值给lzl变量。

  跟浅拷贝一样,此时变量lzl依然新建了一块内存(6203032),此内存记录了list中元素的地址。

  但是,对于list中的元素,深拷贝不是简单的使用原始元素的引用(内存地址)。

  对于list第三个元素(['Python', 'C#', 'JavaScript'])重新生成了一个地址(6203512),此时两个变量的第三个元素的内存引用地址不同。

        3、当对Alex进行修改的时候,由于list中第一个元素“Alex”(str)为不可变类型,所以进行修改的后,第一个元素对应的地址变为了5236064。

  虽然list中第三个元素['Python', 'C#', 'JavaScript'](list)为可变类型,修改后不会产生新的地址。

  但是由于Alex和lzl在第三个元素引用的本就不同,所有Alex的修改对lzl不会产生任何影响

 -------------------------------------------------------------------------------------

其实,对于拷贝有一些特殊情况:

    • 对于非容器类型(如数字、字符串、和其他'原子'类型的对象)没有拷贝这一说。
    • 如果元祖变量只包含原子类型对象,则不能深拷贝。

转载于:https://www.cnblogs.com/visonwong/p/8978408.html

你可能感兴趣的文章
Linux下php连接sql server 2008
查看>>
python字符串格式化
查看>>
golang版try..catch..
查看>>
关于html和CSS的几个基本知识点
查看>>
maven创建webapp项目
查看>>
删除git上已经提交的文件
查看>>
RESTFUL架构
查看>>
【Alpha】Daily Scrum Meeting第七次
查看>>
CF230b: T-primes(简单数论)
查看>>
【转载】设置Windows中gvim的默认配色方案和字体
查看>>
根据年月日,判断20XX年XX月XX日是 星期几
查看>>
迁移文件
查看>>
Nginx的启动、停止与重启
查看>>
**php队列的实现思路和详细过程
查看>>
POJ 2778 DNA Sequence —— (AC自动机+矩阵快速幂)
查看>>
ACM之路(16)—— 数位DP
查看>>
织梦首页常用调用标签
查看>>
关于new String(new byte[]{0})
查看>>
劫持选举 EOJ 3535(随机)
查看>>
javaList容器中容易忽略的知识点
查看>>