学习python的第17天

函数参数传递机制深度解读

值传递机制:

值传递的方式,类似于《西游记》里的孙悟空,它复制一个假孙悟空,假孙悟空具有的能力和真孙悟空相同,可除妖或被砍头。但不管这个假孙悟空遇到什么事,真孙悟空都不会受到任何影响。与此类似,传入函数的是实际参数值的复制品,不管在函数中对这个复制品如何操作,实际参数值本身不会受到任何影响。

实例演示环节

    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两个局部变量在内存中的存储示意图

当程序执行 swap() 函数时,系统进入 swap() 函数,并将主程序中的 a、b 变量作为参数值传入 swap() 函
数,但传入 swap() 函数的只是 a、b 的副本,而不是 a、b 本身。进入 swap() 函数后,系统中产生了 4 个
变量,这 4 个变量在内存中的存储示意图如图 2 所示。


​

如下图

 

当在主程序中调用 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 所示。

函数参数的引用传递

如果实际参数的数据类型是可变对象(列表、字典),则函数参数的传递方式将采用引用传递方式。需要注意的
是,引用传递方式的底层实现,采用的依然还是值传递的方式。

实例示范

    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引用变量(其实就是一个指针)指向字典对象。

这意味着此时内存中有两个东西:对象本身和指向该对象的引用变量,如图

接下来主程序开始调用 swap() 函数,在调用 swap() 函数时,dw 变量作为参数传入 swap() 函数,这里依然
采用值传递方式:把主程序中 dw 变量的值赋给 swap() 函数的 dw 形参,从而完成 swap() 函数的 dw 参数
的初始化。值得指出的是,主程序中的 dw 是一个引用变量(也就是一个指针),它保存了字典对象的地址值,当
把 dw 的值赋给 swap() 函数的 dw 参数后,就是让 swap() 函数的 dw 参数也保存这个地址值,即也会引用
到同一个字典对象。图 5 显示了 dw 字典传入 swap() 函数后的存储示意图。

 

 从该图来看,这种参数传递方式是不折不扣的值传递方式,系统一样也是复制了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 后,在 swap() 函数中失去了对字典对象的引用,不可再访问该字典对象。但主程序中的 dw 变量不受任何影响,依然可以引用该字典对象,所以依然可以输出字典对象的 a、b 元素的值。

 我们由以上可得出以下两个结论:


    不管什么类型的参数,在 Python 函数中对参数直接使用“=”符号赋值是没用的,直接使用“=”符号赋值并不能改变参数。
    如果需要让函数修改某些数据,则可以通过把这些数据包装成列表、字典等可变对象,然后把列表、字典等可变对象作为参数传入函数,在函数中通过列表、字典的方法修改它们,这样才能改变这些数据。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值