【老板叫我了】python的参数传递是「值传递」还是「引用传递」?

2,151 阅读3分钟

前言

2020年6月1日,天气,小雨,工位前

小方啊,这 python 到底是值传递还是引用传递呢

引用传递啊老板

那为什么我看有人说什么不可变对象引用传递,可变对象值传递呢?你快给我好好讲讲

好吧...

可变对象与不可变对象

python 的参数传递是 「引用传递」

要研究这个问题,首先要明白 python 中关于「对象」的定义

python 中「万物皆可对象」

以 java 为对照,我们知道 java 中分为基本数据类型,比如整型 int,字节类型 char,布尔类型 boolean,它们在 java 中不可再分。而对象以基本数据类型和其他对象为基础,结合函数组装而成的,对象包含属性和方法。这就是 java 的数据类型

而在 python 中,无论是表示数字的 number,字符串 string,甚至是函数,它们都是作为对象的。python 中不分基本数据类型和对象,只有可变对象和不可变对象

什么是「不可变对象」呢?

首先我们要明确「变量」的概念。变量是一个指向内存空间的引用,在 c++里我们把它称为指针。

我们在定义一个变量的时候常常会给它赋值a = 1,实际上是把一块存储数据为1的内存空间和引用a联系起来,变量a指向内存空间。我们说的不可变,就是指 这块内存空间存储的值不可变

不信我们可以试一下:定义一个字符串s,修改第一个字符的值

s = 'nihao'
s[0] = 'a'
print(s)
修改不可变对象的执行结果
修改不可变对象的执行结果

我们再来看一下对变量赋值的情况

我们经常会重复修改一个变量的值

a = 10
···
a = 100

借用一个id()内置函数,该函数的作用是获取对象的内存地址,我们用它分别打印变量a每次赋值指向的内存地址

a = 10
print(id(a))
···
a = 100
print(id(100))

可以看到,a每次赋值指向的内存地址都不一样。说明a的第二次赋值并不是把存储的10改成100,而是新建了一块数据为100的内存空间,由a指向新的内存空间。

所以,不可变对象的特点就是,内存空间的值无法被修改,每次赋值都是新建了一块新的内存空间

可变对象就很简单了,对变量的修改都直接作用在指向的内存空间上

参数传递

在参数传递中,我们的参数常常是以变量的形式出现的。参数传递的过程其实是 函数外的变量通过「拷贝」传递给函数的参数

如果拷贝的是内存空间,就是「值传递」,拷贝的是引用,就是「引用传递」

我们再用id()函数看一下参数传递过程中内存地址的变化

a = 10
def test(x):
   print(id(x))
test(a)
print(id(a))

可以看到,参数传递之前「实参指向的内存地址」和传递到函数内部「形参指向的内存地址」是一样的,证明python 的参数传递是引用传递