python的参数传递是值传递还是引用传递?都不是!
【写在前面】
参考文章:
https://www.cnblogs.com/spring-haru/p/9320493.html【偏理论,对值传递和引用传递作了总结】
https://www.cnblogs.com/shizhengwen/p/6972183.html【用实例进行讲解演示】
【正文部分】
值传递(passl-by-value)过程中,被调函数的形式参数作为被调函数的局部变量处理,即在堆栈中开辟了内存空间来存放由主调函数放进来的实参的值,从而想成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。【就给你一个值,你自己做个副本就好】
引用传递(pass-by-reference)过程中,被调函数的形式参数虽然也作为局部变量在堆栈中开辟了内存空间,但这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过堆栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做任何的操作都影响了主调函数中的实参变量。【给你一份我的地址,可以根据这个随时找我,你还能在我家吃个饭啥的】
名词解释:
1、变量与对象
Python 中一切皆为对象,数字是对象,列表是对象,函数也是对象,任何东西都是对象。而变量只是对象的一个引用,对象的操作都是通过引用来完成的。而数据类型是针对【对象】而言的,不是针对【变量】。
2、引用:
可以理解为对对象的内存地址指向。
3、赋值
赋值操作的本质就是绑定一个新的对象,对于不可变数据类型,相当于绑定了一个新的对象,所以进行到是值传递的形式,赋值操作完成之后变量引用的对象发生了变化。args=2执行之前,arg拿到了实参变量a的值,成为一个副本对象,对arg进行赋值操作的时候,都是只作为局部变量进行,不会对主函数的实参变量a造成影响。
def foo(arg): arg = 2 print(arg) a = 1 foo(a) # 输出:2 print(a) # 输出:1
而对于可变数据类型,具有增删改查的特性,进行增删改查的时候并没有赋值操作,所以没有绑定新的对象,对同一个引用或称为同一个对象进行增删改查之后,变量指向的还是该对象。所以进行的是引用传递的形式。arg在执行append之前,实参变量b把自己引用对象的地址也给了arg,所以对arg进行操作的时候对引用对象b也进行了修改。
def bar(args): args.append(1) b = [] print(b)# 输出:[] print(id(b)) # 输出:4324106952 bar(b) print(b) # 输出:[1] print(id(b)) # 输出:4324106952
结论:
python不允许程序员选择采用传值还是传引用。python参数传递采用的肯定是“传对象引用”的方式。这种方式相当于传值和传引用的一种综合。如果函数收到的是一个不可变对象(数字、字符或元组)的引用,就不能直接修改原始对象--相当于通过‘值传递’来传递对象。如果函数收到的是一个可变对象(字典、列表)的引用,就能修改对象的原始值--相当于‘传引用’来传递对象。
【写在最后】
在准备秋招的时候看到一道面试题,所以决定认真的查一下python的参数传递是怎样的,上面两个链接是自己找到的讲解的比较好的博文,本篇博客是自己结合两个博文进行了整理学习,如果有写得不到位的地方可以去原博客去看看。
博主支持原创也尊重原创,如有侵权,联系博主删帖,欢饮监督,转帖请注明出处!