Python中的必考问题1

下面这段代码的输出结果是什么?请解释。

1
2
3
4
5
6
7
8
9
10
11
12
13

def extendList(val, list=[]):
list.append(val)
return list


list1 = extendList(10)
list2 = extendList(123, [])
list3 = extendList('a')

print("list1 = %s" % list1)
print("list2 = %s" % list2)
print("list3 = %s" % list3)

上面代码输出结果将是:

1
2
3
list1 = [10, 'a']
list2 = [123]
list3 = [10, 'a']

很多人都会误认为 list1=[10]list3=['a'],因为他们以为每次 extendList 被调用时,列表参数的默认值都将被设置为 [],但实际上并不是这样,新的默认列表在函数被定义的那一刻只会创建一次。

extendList 被调用时,如果没有指定特定参数,默认的 list 的值随后将被使用。这是因为默认值参数会在函数被定义的时候被创建和计算,而不是在被调用的时候被创建和计算。因此 list1list3 指向的是同一个对象,也就是默认列表。而 list2 是函数被调用时另外指定了一个对象,而不是使用默认的。

画图来分步理解一下:

1
2
3
def extendList(val, list=[]):
list.append(val)
return 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'

所有的操作已经执行完,接下来进行打印输出。此时的 list1list3 指向了同一个列表对象,即定义函数时的默认列表。而 list2 指向的是它调用函数时手动传给函数的另一个列表对象。

1
2
3
print("list1 = %s" % list1)
print("list2 = %s" % list2)
print("list3 = %s" % list3)

于是输出结果就是:

1
2
3
list1 = [10, 'a']
list2 = [123]
list3 = [10, 'a']

我们可以在函数中使用 id() 方法获取函数操作的 list 的内存地址来验证操作的是否是同一个对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
def extendList(val, list=[]):
list.append(val)
print(id(list))
return list


list1 = extendList(10)
list2 = extendList(123, [])
list3 = extendList('a')

print("list1 = %s" % list1)
print("list2 = %s" % list2)
print("list3 = %s" % list3)

执行结果:

1
2
3
4
5
6
140494594992264
140494594992328
140494594992264
list1 = [10, 'a']
list2 = [123]
list3 = [10, 'a']
有钱任性,请我吃包辣条
0%