python函数参数传递机制_Python函数参数传递机制(超级详
细)
Python 的参数值是如何传⼊函数的呢?这是由 Python 函数的参数传递机制来控制的。Python 中函数的参数传递机制都是“值传递”。所谓值传递,就是将实际参数值的副本(复制品)传⼊函数,⽽参数本⾝不会受到任何影响。
Python ⾥的参数传递类似于《西游记》⾥的孙悟空,它复制⼀个假孙悟空,假孙悟空具有的能⼒和真孙悟空相同,可除妖或被砍头。但不管这个假孙悟空遇到什么事,真孙悟空都不会受到任何影响。与此类似,传⼊函数的是实际参数值的复制品,不管在函数中对这个复制品如何操作,实际参数值本⾝不会受到任何影响。
下⾯程序演⽰了函数参数传递的效果:
def swap(a , b) : # 下⾯代码实现a、b变量的值交换 a, b = b, a print("swap函数⾥,a的值是", a, ";b的值是", b) a = 6 b = 9 swap(a , b) print("交换结束后,变量a的值是", a , ";变量b的值是", b)
运⾏上⾯程序,将看到如下运⾏结果:
swap函数⾥,a的值是 9 ;b的值是 6
交换结束后,变量a的值是 6 ;变量b的值是 9
从上⾯的运⾏结果来看,在 swap() 函数⾥,a 和 b 的值分别是 9、6,交换结束后,变量 a 和 b 的值依然是 6、9。从这个运⾏结果可以看出,程序中实际定义的变量 a 和 b,并不是 swap() 函数⾥的 a 和 b 。
正如前⾯所讲的,swap() 函数⾥的 a 和 b 只是主程序中变量 a 和 b 的复制品。下⾯通过⽰意图来说明上⾯程序的执⾏过程。
上⾯程序开始定义了 a、b 两个局部变量,这两个变量在内存中的存储⽰意图如图 1 所⽰。
图 1 主栈区中 a、b 变量存储⽰意图
当程序执⾏ swap() 函数时,系统进⼊ swap() 函数,并将主程序中的 a、b 变量作为参数值传⼊ swap() 函数,但传⼊ swap() 函数的只是 a、b 的副本,⽽不是 a、b 本⾝。进⼊ swap() 函数后,系统中产⽣了 4 个变量,这 4 个变量在内存中的存储⽰意图如图 2 所⽰。
图 2 主栈区的变量作为参数值传⼊ swap() 函数后存储⽰意图
当在主程序中调⽤ swap() 函数时,系统分别为主程序和 swap() 函数分配两块栈区,⽤于保存它们的
局部变量。将主程序中的 a、b 变量作为参数值传⼊ swap() 函数,实际上是在 swap() 函数栈区中重新产⽣了两个变量 a、b,并将主程序栈区中 a、b 变量的值分别赋值给swap() 函数栈区中的 a、b 参数(就是对 swap() 函数的 a、b 两个变量进⾏初始化)。此时,系统存在两个 a 变量、两个 b 变量,只是存在于不同的栈区中⽽⼰。
程序在 swap() 函数中交换 a、b 两个变量的值,实际上是对图 2 中灰⾊区域的 a、b 变量进⾏交换。交换结束后,输出 swap() 函数中a、b 变量的值,可以看到 a 的值为 9,b 的值为 6,此时在内存中的存储⽰意图如图 3 所⽰。
图 3 swap() 函数中 a、b 交换之后的存储⽰意图
对⽐图 3 与图 1,可以看到两个⽰意图中主程序栈区中 a、b 的值并未有任何改变,程序改变的只是 swap() 函数栈区中 a、b 的值。这就是值传递的实质:当系统开始执⾏函数时,系统对形参执⾏初始化,就是把实参变量的值赋给函数的形参变量,在函数中操作的并不是实际的实参变量。
python新手函数根据 Python 的参数传递机制,我们知道:传⼊函数的只是参数的副本,因此程序在函数中对参数赋值并不会影响参数本⾝。如果参数本⾝是⼀个可变对象(⽐如列表、字典等),此时虽然 Python 采⽤的也是值传递⽅式,但许多初学者可能会对这种类型的参数传递产⽣⼀些误会。下⾯程序⽰范了这种类型的参数传递的效果:
def swap(dw): # 下⾯代码实现dw的a、b两个元素的值交换 dw['a'], dw['b'] = dw['b'], dw['a'] print("swap函数⾥,a元素的值是",
dw['a'], ";b元素的值是", dw['b']) dw = {'a': 6, 'b': 9} swap(dw) print("交换结束后,a元素的值是", dw['a'], ";b元素的值是", dw['b'])
运⾏上⾯程序,将看到如下运⾏结果:
swap函数⾥,a元素的值是 9 ;b元素的值是 6
交换结束后,a元素的值是 9 ;b元素的值是 6
从上⾯的运⾏结果来看,在 swap() 函数⾥,dw 字典的 a、b 两个元素的值被交换成功。不仅如此,当 swap() 函数执⾏结束后,主程序中dw 字典的 a、b 两个元素的值也被交换了。这很容易造成⼀种错觉:在调⽤ swap() 函数时,传⼊ swap() 函数的就是 dw 字典本⾝,⽽不是它的复制品。但这只是⼀种错觉,下⾯还是结合⽰意图来说明程序的执⾏过程。
程序开始创建了⼀个字典对象,并定义了⼀个 dw 引⽤变量指向字典对象,这意味着此时内存中有两个东西:对象本⾝和指向该对象的引⽤变量。此时在系统内存中的存储⽰意图如图 4 所⽰:
图 4 主程序创建了字典对象后存储⽰意图
接下来主程序开始调⽤ swap() 函数,在调⽤ swap() 函数时,dw 变量作为参数传⼊ swap() 函数,同样采⽤值传递⽅式:把主程序中 dw 变量的值赋给 swap() 函数的 dw 形参,从⽽完成 swap() 函数的 dw 参数的初始化。值得指出的是,主程序中的 dw 是⼀个引⽤变量(也就是⼀个指针),它保存了字典对象的地址值,当把 dw 的值赋给 swap() 函数的 dw 参数后,就是让 swap() 函数的 dw 参数也保存这个地址值,即也会引⽤到同⼀个字典对象。图 5 显⽰了 dw 字典传⼊ swap() 函数后的存储⽰意图。
图 5 dw 字典传⼊ swap() 函数后存储⽰意图
从图 5 来看,这种参数传递⽅式是不折不扣的值传递⽅式,系统⼀样复制了dw 的副本传⼊ swap() 函数。但由于 dw 只是⼀个引⽤变量,因此系统复制的是 dw 变量,并未复制字典本⾝。
当程序在 swap() 函数中操作 dw 参数时,由于 dw 只是⼀个引⽤变量,故实际操作的还是字典对象。此时,不管是操作主程序中的 dw 变量,还是操作 swap() 函数⾥的 dw 参数,其实操作的都是它们共同引⽤的字典对象,它们引⽤的是同⼀个字典对象。因此,当在 swap()函数中交换 dw 参数所引⽤字典对象的 a、b 两个元素的值后,可以看到在主程序中 dw 变量所引⽤字典对象的 a、b 两个元素的值也被交换了。
为了更好地证明主程序中的 dw 和 swap() 函数中的 dw 是两个变量,在 swap() 函数的最后⼀⾏增加如下代码:
#把dw 直接赋值为None,让它不再指向任何对象
dw = None
运⾏上⾯代码,结果是 swap() 函数中的 dw 变量不再指向任何对象,程序其他地⽅没有任何改变。主程序调⽤ swap() 函数后,再次访问dw 变量的 a、b 两个元素,依然可以输出 9、6。可见,主程序中的 dw 变量没有受到任何影响。实际上,当在 swap() 函数中增加“dw =None”代码后,在内存中的存储⽰意图如图 6 所⽰。
图 6 将 swap() 函数中的 dw 赋值为 None 后存储⽰意图
从图 6 来看,把 swap() 函数中的 dw 赋值为 None 后,在 swap() 函数中失去了对字典对象的引⽤,不可再访问该字典对象。但主程序中的 dw 变量不受任何影响,依然可以引⽤该字典对象,所以依然可以输出字典对象的 a、b 元素的值。
通过上⾯介绍可以得出如下两个结论:
不管什么类型的参数,在 Python 函数中对参数直接使⽤“=”符号赋值是没⽤的,直接使⽤“=”符号赋值并不能改变参数。
如果需要让函数修改某些数据,则可以通过把这些数据包装成列表、字典等可变对象,然后把列表、字典等可变对象作为参数传⼊函数,在函数中通过列表、字典的⽅法修改它们,这样才能改变这些数据。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论