下面这段代码的输出结果是什么?请解释。
1 |
|
上面代码输出结果将是:
1 | list1 = [10, 'a'] |
很多人都会误认为 list1=[10]
,list3=['a']
,因为他们以为每次 extendList
被调用时,列表参数的默认值都将被设置为 []
,但实际上并不是这样,新的默认列表在函数被定义的那一刻只会创建一次。
当 extendList
被调用时,如果没有指定特定参数,默认的 list
的值随后将被使用。这是因为默认值参数会在函数被定义的时候被创建和计算,而不是在被调用的时候被创建和计算。因此 list1
和 list3
指向的是同一个对象,也就是默认列表。而 list2
是函数被调用时另外指定了一个对象,而不是使用默认的。
画图来分步理解一下:
1 | def extendList(val, list=[]): |
定义函数,设置位置参数 val
,默认参数 list
指向空列表。
1 | list1 = extendList(10) |
调用函数 extendList
,并使用默认参数 list
,函数执行过程中向列表中追加元素。空列表追加元素后,第一个位置指向了 10
1 | list2 = extendList(123, []) |
调用函数 extendList
,指定了另外一个空列表作为参数,而不是使用默认参数 list
。函数执行过程中向手动指定的空列表中追加元素 123
。
1 | list3 = extendList('a') |
调用函数 extendList
,并使用默认参数 list
,此时默认参数 list
所指向的列表已经有了元素,函数执行过程中向列表中追加元素,列表中的第二个位置指向了 'a'
。
所有的操作已经执行完,接下来进行打印输出。此时的 list1
和 list3
指向了同一个列表对象,即定义函数时的默认列表。而 list2
指向的是它调用函数时手动传给函数的另一个列表对象。
1 | print("list1 = %s" % list1) |
于是输出结果就是:
1 | list1 = [10, 'a'] |
我们可以在函数中使用 id()
方法获取函数操作的 list
的内存地址来验证操作的是否是同一个对象:
1 | def extendList(val, list=[]): |
执行结果:
1 | 140494594992264 |