Python 手册的 Tutorial.pdf 中 “ 4.7.1 参数默认值” 有如下的例子:
def f(a, L=[]):
L.append(a)
return L
print(f(1))
print(f(2))
print(f(3))
这将打印出
[1]
[1, 2]
[1, 2, 3]
如果你不想要在后续调用之间共享默认值,你可以这样写这个函数:
def f(a, L=None):
if L is None:
L = []
L.append(a)
return L
我家高中生刚学编程,把程序改为如下进行测试,问我 f3 和 f1 的 L 到底差别在哪儿,把我搞懵了,哪个能给出一个简单、初学编程的人听得懂的解释(我只能给他解释 f1 的 L 是可变对象,f3 的 L 是不可变对象?)
def f1(a, L=[]):
print("id(L) = ", id(L))
print("L = ", L)
print()
L.append(a)
return L
def f3(a, L=None):
print("id(L) = ", id(L))
print("L = ", L)
if L is None: # 为何每次成立?
L=[]
print("id(L) = ", id(L))
print()
L.append(a)
return L
if __name__ == "__main__":
f1(1)
f1(2)
f1(3)
print('-'*40)
f3(1)
f3(2)
f3(3)
执行时打印出:
id(L) = 2405815737608
L = []
id(L) = 2405815737608
L = [1]
id(L) = 2405815737608
L = [1, 2]
----------------------------------------
id(L) = 1983976656
L = None
id(L) = 2405815759368
id(L) = 1983976656
L = None
id(L) = 2405815759368
id(L) = 1983976656
L = None
id(L) = 2405815759368
1
densuc 2019-06-16 10:32:47 +08:00 via iPhone
用的 2.7 版本?好像 2 和 3 版本的变量带入是不同的。。。
|
2
BingoXuan 2019-06-16 10:37:52 +08:00 via Android 1
很明显就是函数定义时候这个默认变量就已经初始化了,但调用函数时候,就算重新赋值,也不会修改原变量。也就是函数和其默认参数的作用域是一样。就像你定义一个变量后,再定义函数并传入。你可以用 inspect 模块看一下,你会发现 f1 的默认参数值都会变。其实这个是个坑,我记得某家公司就是被这个特性( bug )搞挂了。
|
3
youngce 2019-06-16 10:43:18 +08:00
```python
def f(a, L=[]): L.append(a) return L print(f(1),f.__defaults__) # [1] ([1],) print(f(2),f.__defaults__) # [1, 2] ([1, 2],) print(f(3),f.__defaults__) # [1, 2, 3] ([1, 2, 3],) ``` 不知道有没有帮助,总之 python 里面没有原生的函数,都是一堆对象 |
4
princelai 2019-06-16 10:44:51 +08:00 via Android 1
等号左边的 L 存储的是一个栈地址,当等号右边是可变对象是,赋值为一个可变的堆对象地址,也就是指针,当等号右边是个不可变常量时,存储该值的地址。Python 的参数传递是引用传递,给个可变对象意味着这是外部对象的指针,给个不可变对象,然后你又在内部从新赋值为[],L 一直是内部变量
|
5
azh7138m 2019-06-16 10:44:56 +08:00
f1 每次的默认参数都是同一个 '[]'
f3 每次的默认参数都是同一个 'None' > Python ’ s default arguments are evaluated once when the function is defined, not each time the function is called |
6
Xs0ul 2019-06-16 10:49:09 +08:00
楼主想问的是为什么 f3 运行得到的 list 的 id 还是一样的?
你试试 l1 = f3(1) l2 = f3(2) l3 = f3(3) 或者 f3(1) a = [] print(id(a)) f3(2) f3(3) f1 里一样是因为相当于提前创建了一个 list,把这个 list 作为默认参数,所以每次都是这一个 f3 里是内部创建了一个新的 list,按道理每次 id 不一定一样。但是因为生成的 list 没被接收,相当于已经废弃,第二次生成的时候或许是重复利用了 /生成了同样的一个 |
7
Takamine 2019-06-16 19:06:15 +08:00 via Android
最好不要用可变类型做入参,很容易有坑。(。ò ∀ ó。)
|