Python修改函数参数?

有很多次尝试修改函数参数的值,因为不知道究竟能不能改,所以每次都写个函数测试一下。经过若干次的“测试”,发现还是没有明确的结论。好像对于不同类型的参数,结果不同。最终,在stackoverflow上面找到了问题的答案

先猜下这段代码的输出:
[ccb_python]
def f(n, x):
n = 2
x.append(4)
print ‘In f():’, n, x

def main():
n = 1
x = [0,1,2,3]
print ‘Before:’, n, x
f(n, x)
print ‘After: ‘, n, x

main()
[/ccb_python]

c语言的函数修改参数,参数类型必须为指针才可以。c++则是通过传递“引用”的方式。那么Python有类似的处理方式吗?

其实每次遇到这个问题,我真的很希望能用个“&”解决。可惜,不能。因为Python的“变量”和c/c++里的“变量”根本不是一回事儿。“变量”这个词用在Python里面其实是不太合适的。更合适的说法应该是“标识符”。看看这个就全明白了。

Python的变量,仅仅是指向某对象的引用而已。
[ccb_python]
>>> a = 1
>>> b = 1
>>> id(a) == id(b)
True
>>> id(a) # the first object’s memory address
39772088L
>>> a = 2
>>> id(a) # the second object’s memory address
39772064L
>>> id(b)
39772088L
[/ccb_python]
开始a和b是指向同一个对象的引用。将一个新的值赋给a后,39772088L这个地址对应的对象没有改变,仍然是1。只是a指向了一个新的对象2,不再指向原来的对象1。

无论变量原来指向的是什么类型的对象,赋值操作都不会改变对象的内容。而是把变量从指向一个对象的引用,改为指向另一个对象的引用
[ccb_python]
>>> c = [1, 2, 3]
>>> id(c)
49799624L
>>> c = [1, 2, 3]
>>> id(c)
49750088L
[/ccb_python]
所以,不管是在函数里面还是函数外,赋值的操作都无法修改变量引用地址的对象。
上面的例子里,虽然创建了两个相同的列表,但是和前一个例子不同的是这次id返回的值却不同。原因在于list是可变(mutable)类型,而int是不可变(immutable)类型。

弄清楚上面这个问题,已经解决了一大半了。还得继续深入了解下Python函数调用参数传递的方式:参数是按值传递的(passes references-to-objects by value)。只不过传递的值是对某个对象的引用,而不是这个对象的值。

听起来觉得很简单,但是这样的方式造成的表现就是,有时候看起来是传引用,有时候又像是传值。比如最开始的那段代码,两个参数n和x,最终结果是n没变,x变了。列表x发生了改变,看起来是传递了引用。但是同时n没发生变化,又看起来像是传值。

综合前面的这些,因为通过赋值不能改变对象的值,所以n没有变化(注意这点与对象是mutable还是immutable无关,即使在函数里把一个新的列表赋给x,x也不会发生任何变化)。又因为x是可变类型,自身有append这样的函数,所以可以通过这种函数来修改对象(immutable类型没有这样的函数)。