图 | Pexels
日期 | 2021.1.3
学了一段时间Python的朋友都会有一个疑问,Python的函数入参到底是传值,还是引用?
这个问题蛮有意思的,在C/C++中,函数参数传递是存在传值的,如果把刚刚那个问题给理解清楚了,自己对Python的理解有更深一步。
在解答这个问题前,我们先来说一下什么是传值,什么是传引用。
- 传值:
按通俗的话来说,就是在内存中有一个地址,我也有一个抵制,我把我的地址复制给你后,以后你利用它做什么事都和我毫不相干,简而言之,这不会改变原来参数的内容。
- 传引用:
有个参数,在内存中有个地址,地址里面放了一些杂物,在调用函数时,把实际参数的地址传递到该函数中,在这个过程中对参数进行了修改,从而影响到了实际的参数,总的来说,就是函数在运行完后会改变原有的参数内容。
至于Python是怎么做到的,我们先来看一个例子:
a=1,b=a,b=2
- 这个在C/C++里面执行b=a的时候,其实是在内存里面申请一块内存把a的值复制到内存中,当执行b=2的时候,是把b对应的值从1修改成2,如图:
但是在Python里面的赋值并不是复制,b=a的操作使得b与a引用同一个对象(注意是对象),而b=2则是b指向2,如图:
不信我们可以在程序里面验证:
a=1
print(id(a))
>>>33989408
b=a
print(id(b)) #b=a之后b的id()值和a一样
>>>33989408
b=2
print(id(b))
>>>33989396 #b=2之后b指向对象2,id()值发生了改变
print(id(a))
>>>33989408
从程序里面写可以看出:
- b=a赋值后b的id()和a一样,b=2之后b指向了另外一块空间,其实b=a传递的是对象的引用,它们指向同一块内存.
- 当b=2之后b又重新指向了2所代表的对象上去,而此时1只有a指向.
当函数add()调用完之后,函数体中的局部变量在函数体外不可见,此时的n代表函数体外的命名空间所对应的n,所以其值还是10。
结论:Python函数参数传递的是对象的引用,参数传递的过程中将整个对象传入.
对于可变的对象的修改在函数外部和内部都可见,调用者和被调用者共享这个对象。
而对于不可变对象,由于并不能真正被修改,因为修改一般都是通过生成一个新的对象然后赋值来实现的。