foo这只是一个标识符,它可以指向任何东西,包括变量、类、函数、模块、流等。timer是一个返回函数的高阶函数,它的返回值是一个函数,赋值给foo之后,foo也就是一个函数。
这个问题的答案无外乎这几种说法:传值,传引用,对于可变对象是传引用,不可变对象是传值。传引用
先看下面这个例子:
>>>def foo(n):
... print id(n)
... n = 3
... print id(n)
>>>n = 2
>>>id(n)
31030000L
>>>foo(n)
31030000L
31029976L
>>>n
2
>>>id(n)
31030000L
由foo中两次输出不相等可以看出,传引用说法并不成立。
传值
来看下面的例子:
>>>def foo(n):
...print n
...n.append(3)
...print n
>>>n = [1, 2, 4, 8]
>>>foo(n)
[1, 2, 4, 8]
[1, 2, 4, 8, 3]
>>>n
[1, 2, 4, 8, 3]
按传值的说法,一个值传进来,在函数内改动并不会影响变量本身的值,上面例子中n变量本身的值也被改变了,说明传值的说法也不对。
3.可变对象传引用,不可变对象传值
相比上面两种说法,这种说法似乎更靠谱,传播也更为广泛,那它到底对不对呢?
>>>def foo(n):
...print id(n)
...n = ['1', '2', '3']
...print id(n)
...print n
>>>n = [1,2,3,4,5,6]
>>>id(n)
35637576
>>>foo(n)
35637576
35916168
['1', '2', '3']
>>>n
[1, 2, 3, 4, 5, 6]
按照可变对象传引用的说法,上面list类型是可变对象,应该传引用,这foo方法中两次调用id应该输出一样的值,更改的结果也应该影响到外部变量,但结果显然不是这样的,这说明,这种说法也是不正确的。
那么Python传值的方法到底是什么样呢?其实Python中的函数参数所遵循的是传对象(call by object),或者叫做穿对象的引用(call by object reference)。在调用函数时,将变量整个对象传入,对于可变对象的修改,在函数内外均可见;而对于不可变对象,因为其并不能真正意义上被赋值,修改是通过生成新的对象来实现的。
下面来一个有趣的例子作为结尾:
>>>def bar(a = []):
...print id(a)
...a.append(7)
...print a
>>>for _ in range(5):
...bar()
#结果输出请自己动手实践,原因应该不难理解