Python中函数参数传递的本质——引用传递

文章目录

  • 1. 问题引入
  • 2. 问题解答
    • 2.1 不可变类型
    • 2.2 可变类型
  • 3. 结论

在Python中变量赋值的本质中,我们知道了,在Python中,声明一个变量并赋值的过程实际上是:变量名所代表的内存地址处保存了数据值存储的内存地址,并称该过程为引用

下面,我们基于上述结论,深入探讨Python中函数参数传递的本质。

1. 问题引入

首先,我们来看一段简单的代码,请你先脑补一下这段代码的输出。

num = 10
nums = [11, 22]


def test(num):
    num += 10


def test2(nums):
    nums.append(33)


test(num)
test2(nums)

print("调用test函数后,num = ", num)
print("调用test2函数后,nums = ", nums)

实际上,执行完上述代码后,输出为:

调用test函数后,num = 10
调用test2函数后,nums = [11, 22, 33]

即,变量num的值没有被修改成20,但是变量nums被成功追加了33。下面,我们深入探讨一下为什么会有这样的结果。

2. 问题解答

2.1 不可变类型

Python中函数参数传递的本质——引用传递_第1张图片

首先,如上图所示,声明变量并赋值的过程a = 10如Python中变量赋值的本质所述(如上图步骤1)。

其次,定义test函数声明形参num(实际上,形参变量名可以是任何符合Python编程规范的名称)后,调用函数test并传递参数的过程对应于上图中的步骤2,即:此步骤后,有两个内存地址处(恰巧其别名都是num)存储了相同的数据存储地址(0x1002)。

然后,如下图所示,当执行了num += 10后,因为Python中数字为不可变类型,所以计算机将:
a. 开辟一块新的内存(地址为0x1004)用以存储数据20;
b. 变量num所代表的地址处存储的数据地址由0x1002变为0x1004。

Python中函数参数传递的本质——引用传递_第2张图片

由此,当最后执行打印语句时,Python解释器所能找到的num仍是代码开始声明赋值的那个(定义在函数内部的变量,其无法在函数外部被访问),而由上图可知,其保存的地址还是0x1002,故取值仍为10。

2.2 可变类型

Python中函数参数传递的本质——引用传递_第3张图片

如上图,对于可变类型,其步骤1、2和上述不可变类型一致。

但区别在于,如下图所示,当执行nums.append(33)时,因为Python中列表是可变类型,所以不会开辟新的内存空间,即两个列表变量的地址处指向了相同的数据地址。

Python中函数参数传递的本质——引用传递_第4张图片

由此,最后执行打印语句时,通过代码开头声明赋值的变量找到的数据地址虽然还是0x1006,但是其值已经被修改成了[11, 22, 33](这也就是所谓数据“可变”的含义)

3. 结论

综上可知:

在Python中,函数传递参数是通过引用的方式,而非数据值传递;
在Python中,可变类型包括列表、字典,不可变类型包括数字、元组、字符串等,故上述现象对这些类型均试用。

你可能感兴趣的:(#,高级语法)