定义有默认参数的函数时,确实为我们提供了方便。但是如果默认参数为可变数据类型时,就应该注意了。
下面来看一道在多次笔试中出现的题:
def f(x, l = []): #pycharm中空列表会代码高亮,警告默认参数是可变的(Default argument value is mutable)
print('l = ',l,'******')
for i in range(x):
l.append(i*i)
print(l)
f(2)
f(3,[3,2,1])
f(3)
#运行结果
l = [] ******
[0, 1]
l = [3, 2, 1] ******
[3, 2, 1, 0, 1, 4]
l = [0, 1] ******
[0, 1, 0, 1, 4]
Process finished with exit code 0
这道题被要求手写,不注意的肯定会掉入f(3)的坑中,写个[0,1,4]。这是为什么呢?当可变参数l为默认时,每调用运行一次该函数,都会使参数l发生改变。
来看一个简单的例子原文:
def f(l=[]): # 其实这里写的时候pycharm就会有警告提示:默认参数是可变的
l.append(1)
return l
#改变了默认参数的值
print(f())
#当使用默认参数时的函数调用会受影响
print(f())
#传入参数时的函数调用不受影响
print(f([3, 3]))
#运行结果:
[1]
[1, 1]
[3, 3, 1]
那如何纠正呢(其他可变类型类似,推荐第二种方法)?
def f(x):
l = []
for i in range(x):
l.append(i*i)
print(l)
f(2)
f(3)
[0, 1]
[0, 1, 4]
Process finished with exit code 0
#第二种方法
def f(l=None):
# 在内部给l赋值
l = l or []
l.append(1)
return l
print(f())
print(f())
print(f([3, 3]))
# 运行结果:
[1]
[1]
[3, 3, 1]
Process finished with exit code 0
如果还是不理解,请看下面的代码:
def f(x, l = []):
print('l = ',l,'*********空间地址:',id(l))
for i in range(x):
l.append(i*i)
print(l)
f(2)
l = [3,2,1]
print('*********空间地址:',id(l))
f(3,l)
f(3)
#运行结果
#f(2)的结果
l = [] *********空间地址: 95694216
[0, 1]
#f(3,[3,2,1])的结果
*********空间地址: 95690888
l = [3, 2, 1] *********空间地址: 95690888
[3, 2, 1, 0, 1, 4]
#f(3)的结果
l = [0, 1] *********空间地址: 95694216
[0, 1, 0, 1, 4]
Process finished with exit code 0
由此可见,当函数f()执行时,使用默认参数l,则l指向的是同一空间地址,所以随着代码的执行,列表l里的元素会不断增加。如果不使用默认参数l=[],即传入参数列表,则指向的是传入列表的空间地址,是一个新的地址空间,不会受默认参数列表的影响。这下应该懂了吧。。。
网友评论