本文主要探究一下Python的函数参数传递方式。这是初学者必须知道的一个知识点,也是面试之中经常出现的问题,这个做一个总结。

对象和变量

Python和一些类C的语言很不一样,在Python中,类型是属于对象的,变量是没有类型的。所有的变量都可以理解是内存中的一个对象的“引用”,或者,也可以看似C中void*。

mutable & immutable

对应于上一个概念,这里引出另一个概念,可更改(mutable)对象与不可更改(immutable)对象。

我们都知道,在Python中,strings, tuples, 和numbers是不可更改的对象,而list,dict等则是可以修改的对象。

可改变和不可改变的含义,看下面的例子:

1
2
3
4
5
6
>>> a = 1
>>> id(a)
26722648
>>> a = 2
>>> id(a)
26722624

内存中原始的1对象因为不能改变,于是被“抛弃”,a指向一个新的int对象,其值为2。很明显发生了变化。

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> b = [1]

>>> id(b)
140444991150560
>>> id(b[0])
26722648

>>> b[0] = 2

>>> id(b)
140444991150560
>>> id(b[0])
26722624

因为list是可改变的,所以,第一个元素变更为2。其实应该说,b指向一个包含一个对象的数组。赋值所发生的事情,是有一个新int对象被指定给b所指向的数组对象的第一个元素,但是对于b本身来说,所指向的数组对象并没有变化,只是数组对象的内容发生变化了。这个看似void*的变量所指向的对象仍旧是刚刚的那个有一个int对象的list。

函数参数传递

根据上面的概念,我们再来研究一下Python函数参数的传递。

不可变对象参数调用:

1
2
3
4
5
6
7
def foo(a):
a = 10

b = 2

foo(b)
print b

结果为:2。

可变对象参数调用

1
2
3
4
5
6
def foo(a):
a[0] = 10

b = [2]
foo(b)
print b

结果为:[10]

Python函数参数传递和变量传值操作是一样的,如果这个变量的值不变,我们看似就是引用,如果这个变量的值改变,我们看着像是在赋值。