Python函数的参数传递
1. C++中函数的参数传递
C++中常见的参数传递有值传递和引用传递两种:
- 值传递:拷贝参数的值,传递给函数里的新变量。原变量和新变量之间互相独立,互不影响。
- 引用传递:把参数的引用传递给新的变量,原变量和新变量就会指向同一块内存地址。
1.1 参数传递:
#include <iostream>
using namespace std;
// 交换 2 个变量的值
void swap(int x, int y) {
int temp;
temp = x; // 交换 x 和 y 的值
x = y;
y = temp;
return;
}
int main () {
int a = 1;
int b = 2;
cout << "Before swap, value of a :" << a << endl;
cout << "Before swap, value of b :" << b << endl;
swap(a, b);
cout << "After swap, value of a :" << a << endl;
cout << "After swap, value of b :" << b << endl;
return 0;
}
Before swap, value of a :1
Before swap, value of b :2
After swap, value of a :1
After swap, value of b :2
上面的swap()函数使用值传递,把a,b的值分别拷贝给x和y,然后再交换x和y的值,故不影响a,b的值。
1.2 引用传递:
将上面的swap()函数改为:
void swap(int& x, int& y) { # &表示取地址
int temp;
temp = x; // 交换 x 和 y 的值
x = y;
y = temp;
return;
}
使用引用传递后,x和a,y和b指向的就是同一块内存区域,故swap()中交换x,y就是交换a,b。
2. Python中的参数传递
Python中的参数是赋值传递(pass by assignment),或者叫对象的引用传递(pass by object reference) 。Python中的所有数据类型都是对象,所以参数传递时,只是让新变量与原变量指向相同的对象而已。
也就是说,在python中:
- 修改immutable变量的内容核心在于修改这个变量引用本身来指向新的内存区域,而不是修改变量指向的内存区域的内容。
- 对于mutable变量,对其进行修改就是对其指向的内存区域的内容进行修改。
2.1 immutable变量的参数传递
def my_func1(b):
b = 2 # b指向了新的内存区域
a = 1
my_func1(a)
a
=================
1
以上代码,实际上就是两步:
- 局部变量b指向了a,即a,b指向了同一个内存区域,都指向了1
- 在函数内,b指向了新的内存区域,指向了2;a不变
要修改a变量,就只能让a变量指向新的内存区域,即:
def my_func2(b):
b = 2
return b
a = 1
a = my_func2(a)
a
=======================
2
2.2 mutable变量的参数传递
def my_func3(l2):
l2.append(4)
l1 = [1, 2, 3]
my_func3(l1)
l1
[1, 2, 3, 4]
以上的代码分为两步:
- l2指向了l1
- l2.append(4)就是对l1,l2共同指向的列表进行append操作
要注意的是,mutable变量的传递具体要看函数具体的操作是什么样子,因为python函数内部也可以开辟新的内存空间,这样就和immutable变量的情况一样了。如:
def my_func4(l2):
l2 = l2 + [4]
l1 = [1, 2, 3]
my_func4(l1)
l1
[1, 2, 3]
l2 = l2 + [4]
上面的代码实际上开辟了新的内存空间存储列表l2原先的内容和列表[4]的内容,然后让l2指向该新的内存区域。这和immutable变量的情形是一样的操作。如下所示:
def my_func4(l2):
print(f"l2pre_id:{id(l2)}")
l2 = l2 + [4]
print(f"l2pos_id:{id(l2)}")
l1 = [1, 2, 3]
print(id(l1))
my_func4(l1)
print(l1)
print(id(l1))
==========================
88012680
l2pre_id:88012680
l2pos_id:87985736
[1, 2, 3]
88012680
可见l2指向了新的内存区域。要注意的是,若 l2 = l2 + [4]改写为l2 += [4],其实质就和l2.append(4)一样,还是在原内存区域上做添加操作。