鱼C论坛

 找回密码
 立即注册
查看: 2920|回复: 9

[学习笔记] 【赋值“=”的真正意义--值传递和引用传递、深浅拷贝】

[复制链接]
发表于 2018-12-15 19:26:03 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 heidern0612 于 2018-12-21 08:23 编辑

写心得的过程都是自我思考的过程,借鉴了很多论坛前辈和互联网大佬的经验,仓促惶恐间难免漏洞百出,如有错误,恳请指出,不胜感激。


声明:本帖内容不回复不影响阅读


这几天看书发现个有趣的例子,琢磨了挺长时间,有点超纲,不扯这个例子,先上3个简单的例子热热身:

例1:不可变对象赋值
  1. a = 1
  2. b = a
  3. b = a+1
复制代码


最后a和b的值一样吗?
游客,如果您要查看本帖隐藏内容请回复



例2:可变对象赋值
  1. a=[1]
  2. b=a
  3. a[0]=2
复制代码


最后a和b的值一样吗?
游客,如果您要查看本帖隐藏内容请回复



例3:直接赋值
  1. a=[1]
  2. b=[1]
  3. a[0]=2
复制代码


最后a和b的值一样吗?
游客,如果您要查看本帖隐藏内容请回复




从以上3个例子我们可以看出,大多数时候,我可能只是想给a、b初始化相同的值,才用了b=a,在使用的过程中,我并不希望a修改后对b造成影响,或者修改b后,对a造成影响。

但从例1和2来看,b=a,有可能互不影响,有可能会相互影响,要视a的具体值的情况。

我们应当如何理解这种情况,以至不会因为理解上的模糊不清,影响我们实际编程呢?

例1: b=a,实际是将a指向的对象的引用赋值给b,这样a和b就指向了同一个对象。再执行a+1,相当于把a的对象+1,也就是100+1=101,对象变了,b自然也就变了。

例2: 执行a[0]=2,修改的是对象[1]第一个元素的值,a和b所指向的还是这个对象,对象本身变化了,a和b变量看到的值也就都变化了。

例3:执行完a[0]=2后,a和b本身指向发生了变化,变成了指向不同的对象,自然修改a不会影响b。

从以上分析我们可以知道,b=a后,a、b是否会相互影响,关键在于修改的是不是对象本身的内容。

如果修改的是对象本身的内容,则两者会相互影响;如果是创建新对象后直接赋值给上述某个变量,则两者不会相互影响。




下面是我这几天看到的一个例子:

  1. def pattern(obj):
  2.     print("原值为:",obj)
  3.     obj += obj
  4.    
  5. print("******值传递例子******")
  6. string1 = "我的值不会改变"
  7. pattern(string1)  #函数调用
  8. print(f"函数调用后: {string1}")

  9. print("\n\n")

  10. print("******引用传递例子******")
  11. list1 = ["我的值会改变"]
  12. pattern(list1)  #函数调用
  13. print(f"函数调用后: {list1}")
复制代码


看的云里雾里不要紧,先引入下值传递和引用传递的概念:

值传递:方法调用时,实际参数把它的值传递给对应的形式参数,方法执行中形式参数值的改变不影响实际参数的值。

引用传递:也称地址传递,在方法调用时,实际上是把参数的引用(传的是地址,而不是参数的值)传递给方法中对应的形式参数,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,方法执行中形式参数值的改变将会影响实际参数的值。


由上面函数的例子可以看出,python中对一个函数可以传递参数,但是如何分辨是值传递还是引用传递,不是程序员手动控制的,而是python根据你传入的数据对象,自动识别的。

当你传入的参数对象是可变对象,如列表,字典,这个时候就是引用传递,如果参数在函数体内被修改,那么源对象也会被修改。

当你传入的参数对象是不可变的对象:数字,元组,字符串时,就是值传递。源对象是不会改变的。

简单点就一句话:可变对象为引用传递,不可变对象为值传递



实际上Python参数传递采用的肯定是“传对象引用”的方式,这种方式相当于传值和传引用的一种综合。

如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值——相当于通过“传引用”来传递对象;

如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象——相当于通过“传值'来传递对象。

最后附上提到的两个概念:

1.可变对象
标准定义:如果对象的值是可以修改的,则称该对象为可变对象
包含:自定义类型、列表(list)、字典(dict)、可变集合(set)
特征:执行类似a=[1,2,3]后,再执行a[0]=99,实际上是这个对象第一个元素的值改为99;当然,如果是执行a=[1,2,3]后,再执行a=[99,2,3],就是新建对象[99,2,3]后赋值给变量a


2.不变对象
标准定义:如果对象的值不可以修改,则称为不可变对象
包含:数字类型(int、long、float、complex、bool)、字符串类型(str、unicode)、元组(tuple)、不可变集合(frozenset)
特征:执行类似a=3后,再执行a=4,实际上不是将3这个对象所在的内存的值改为4,而是在内存中新建一个对象4,再赋值给变量a




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

既然Python只允许引用传递,那有没有办法可以让两个变量不再指向同一内存地址呢?

答案是有,这就涉及到浅拷贝(copy)和深拷贝(deepcopy)概念。


还是先举一个栗子:




例①:不使用copy的复制,简单理解为复制level 0级,实际上这个根本称不上复制,最多算是重命名。
1.png


我简单的赋值,两者所指向的内存地址是一样的,a列表append个值,b也跟着变了。


这并不是我想要的结果,于是我想到了老师介绍的copy方法。


例②:使用copy以及copy附带的深拷贝,简单理解Copy为level1,DeepCopy理解为level2,或将浅拷贝理解为一层复制也可以。

2.png

从图中我们可以看出,a和b简单的level 0 赋值拷贝已经不能满足我们的要求了,我import了copy模块,这里copy后内存地址果然变了,deepcopy似乎也达到了相同的效果。

从内存地址上看,好像Copy和DeepCopy没什么区别,都是复制了一份相同的原值,改变原值并不会影响相应Copy和DeepCopy的值。


那么Copy和DeepCopy有什么区别呢?

例③:Copy和DeepCopy的区别

我们简单弄个二级列表,重新用Copy和DeepCopy复制下a列表。
3.png

从图中清晰明了可以看出,二级列表内包含的元素1列表Copy和DeepCopy的内存值不同了。

我们append一个新元素[4]进去,重新看下区别:

4.png

所以,以上可以看出,Copy方法实现的只是简单的一层复制,而DeepCopy实现的则是完全的深度拷贝

这就是以上二者的区别,实际上切片的复制也只是简单的浅拷贝(level 1),无法实现二次及以上的复制。

如图:

5.png


评分

参与人数 2荣誉 +10 鱼币 +10 贡献 +6 收起 理由
何以术 + 5 + 5 + 3 感谢楼主无私奉献!
爱学习的懒懒君 + 5 + 5 + 3 讲的很棒

查看全部评分

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-12-23 16:48:43 | 显示全部楼层
312312321
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-2-25 11:31:17 From FishC Mobile | 显示全部楼层
小白,表示看不懂,先收藏,等我下次回头来看
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-3-2 15:25:43 | 显示全部楼层
回复看隐藏,不然研究不出来
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-3-8 17:16:23 | 显示全部楼层
回复看影藏
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-3-12 09:31:53 | 显示全部楼层
?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-3-24 15:57:23 | 显示全部楼层
不一样
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-3-24 19:04:43 | 显示全部楼层
666
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-3-23 16:53:56 | 显示全部楼层
一样
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-4-1 15:29:44 | 显示全部楼层
值是一样的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-25 02:43

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表