关于python之中是是值传递还是引用传递的问题,之前也初学的时候一直有所困扰,但是通过多次的对python内存机制的了解后,其实你会发现一个真理!
在python值传递和引用传递的问题,就会发现在python里讨论这个确实不存在任何的意义!

如果你有了解过我之前写关于内存管理机制的内容的话,大致会明白一个道理:
变量 = 对象
变量保持对象的堆内存的地址,所以是叫做对象的引用!
其实上面我们也可以总结出一个原理:
(对象)堆内存地址 = (变量)栈内存地址 = (变量)对象的引用地址
如果拷贝对象是不可变地址,则共享的是同一个地址(不可变对象共享地址的)
如果拷贝对象是可变,都会生成新的地址
我们的知道我们的python对象分为可变对象和不可变对象。
PS(个人见解):其实上面的图()里面说的值类型其实也有点误导,严格来说其实不算是一个值类型,它只是一个装载其他不可变对象的一个容器.
如下代码:
a= 1
b= 1
print('不可变对象1的地址为(把地址给了a变量):',id(a))
print('不可变对象1的地址为(把地址给了b变量):',id(b))
print('a和b的对象引用地址是否一致:',a is b)
输出结果为:
不可变对象1的地址为(把地址给了a变量):140711622468432
不可变对象1的地址为(把地址给了b变量):140711622468432
a和b的对象引用地址是否一致:True
a= [1,2,3]
print('[]是可变对象,装载容器内是不可变对象:',id(a))
print('[0]是不可变对象,装载容的对象不可变对象:',id(a[0]))
print('[1]是不可变对象,装载容的对象不可变对象:',id(a[1]))
print('[2]是不可变对象,装载容的对象不可变对象:',id(a[2]))
b =[1,2,3]
print('b[0]是不可变对象,和a[0]是不可对象地址比较:',id(a[0]),id(b[0]))
print('b[0]是不可变对象,和a[0]是不可对象地址比较:',a[0]is b[0])
输出结果为:
[]是可变对象,装载容器内是不可变对象:2568450203016
[0]是不可变对象,装载容的对象不可变对象:140711622468432
[1]是不可变对象,装载容的对象不可变对象:140711622468464
[2]是不可变对象,装载容的对象不可变对象:140711622468496
b[0]是不可变对象,和a[0]是不可对象地址比较:140711622468432 140711622468432
b[0]是不可变对象,和a[0]是不可对象地址比较:True
a = 1
def ceshi(a):
print('传入的1对象的引用的地址是:',id(a))
print('传入的1对象的引用的地址对应值是:', a)
a = 2
print('内层修改我们的变量的引用地址为对象2的堆内存地址:', id(a))
print('内层变量a的指向的对象的值是:', a)
ceshi(a)
print('外层变量a的对象引用地址是:',id(a))
print('外层变量a的指向的对象的值是:',a)
输出结果为:
传入的1对象的引用的地址是:140711622468432
传入的1对象的引用的地址对应值是:1
内层修改我们的变量的引用地址为对象2的堆内存地址:140711622468464
内层变量a的指向的对象的值是: 2
外层变量a的对象引用地址是:140711622468432
外层变量a的指向的对象的值是: 1
分析:引用传递,但是上面示例传递引用后,我们的又分配了一个2的新的堆内存的地址,创建了一个新的变量,所以此时我们的a内层的地址是执行了新创建2的对象的堆内存的地址,(但是不会影响到外层的地址1)
a = [1]
def ceshi(a):
print('传入的1对象的引用的地址是:',id(a))
print('传入的1对象的引用的地址对应值是:', a)
a.append(2)
print('内层修改我们的变量的引用地址为对象2的堆内存地址:', id(a))
print('内层变量a的指向的对象的值是:', a)
ceshi(a)
print('外层变量a的对象引用地址是:',id(a))
print('外层变量a的指向的对象的值是:',a)
输出结果是:
传入的1对象的引用的地址是:2310115150344
传入的1对象的引用的地址对应值是: [1]
内层修改我们的变量的引用地址为对象2的堆内存地址:2310115150344
内层变量a的指向的对象的值是: [1, 2]
外层变量a的对象引用地址是:2310115150344
外层变量a的指向的对象的值是: [1, 2]
分析:上面的传递还是我们的外部[]对象的地址,内部的append方法,操作其实是[]内容的对象,因为我们由始至终[]内容的地址其实一直没改变,变的只是里面的内部装载对象。所以也是一个引用传递!,但是由于内存对对象做了新增对象的的操作,所以我们的对应的原来里面的列表容器内的对象是的值是有变化的!
a = [1]
def ceshi(a):
print('传入的1对象的引用的地址是:',id(a))
print('传入的1对象的引用的地址对应值是:', a)
a = [1] + [2]
print('内层修改我们的变量的引用地址为对象2的堆内存地址:', id(a))
print('内层变量a的指向的对象的值是:', a)
ceshi(a)
print('外层变量a的对象引用地址是:',id(a))
print('外层变量a的指向的对象的值是:',a)
输出结果为:
传入的1对象的引用的地址是:3164470430344
传入的1对象的引用的地址对应值是: [1]
内层修改我们的变量的引用地址为对象2的堆内存地址:3164465840712
内层变量a的指向的对象的值是: [1, 2]
外层变量a的对象引用地址是:3164470430344
外层变量a的指向的对象的值是: [1]
分析:重点 a = [1] + [2] 其实是产生了一个新的对象[]+ [] 这个操作已经是产生了新的堆内存的分配操作,所以分配新的内存地址。
其实没必要谈论是值传递还是引用传递,我们里理解其实是永远是一个引用传递。但是
如果我们的传递到内部之后,涉及到新的对象的创建分配的时候,那么它内部的操作,不会影响到外部的变量指向原来的对象的值的内容
如果我们的传递到内部后。不涉及新的对象的创建分配,则它的操作是对象的值,对外部的原来指向的对象的值会有影响
简书:https://www.jianshu.com/u/d6960089b087
掘金:https://juejin.cn/user/2963939079225608
小钟同学 | 文 【原创】| QQ:308711822
1:本文相关描述主要是个人的认知和见解,如有不当之处,还望各位大佬指正。 2:关于文章内容,有部分内容参考自互联网,如有链接会声明标注;如没有及时标注备注的链接的,如有侵权请联系,我会立即删除处理哟。
原文作者:程序员小钟同学;如有侵权,请联系管理员删除。