python列表数乘里的坑
在对列表进行数乘操作时,列表list中元素如为引用类型(列表、对象实例等),则数乘之后,复制出来的每个引用类型的元素都会指向同一个地址。这用会导致后续修改列表元素时,发生一些意料之外的事。接下来我将举例说明。
情况一:列表元素是列表
比如创建一个2*2的二维列表,每个元素都是0,分别用直接创建、数乘、相加、列表推导式的方法创建:
m = [[0,0],[0,0]]
print('m=',m,'第一个元素地址=',id(m[0]),'第二个元素地址=',id(m[1]))
n = [[0,0]]*2
print('n=',n,'第一个元素地址=',id(n[0]),'第二个元素地址=',id(n[1]))
p = [[0,0]]+[[0,0]]
print('p=',p,'第一个元素地址=',id(p[0]),'第二个元素地址=',id(p[1]))
q = [[0,0] for i in range(2)]
print('q=',q,'第一个元素地址=',id(q[0]),'第二个元素地址=',id(q[1]))
用函数id()可以取得四种情况下的列表元素地址:
可以看到使用数乘方法创建的二维列表n的两个[0,0]元素地址相同,因而如果修改其中一个元素,另一个元素元素随之改变,而这是我们大部分情况所不希望的:
n[1][0] = 1
print(n) #输出[[1, 0], [1, 0]]
而使用其它方法创建的二维列表则不会出现上述情况:
q[1][0] = 1
print(q) #输出[[0, 0], [1, 0]]
情况二:列表元素是对象实例
如果列表元素是一个类的实例时, 也会受到影响:
class A():
value = 10
a = A()
list1 = [a]
list2 = list1 * 2
print(list1[0].value) # 输出10
print(list2[0].value,list2[1].value) # 输出10 10
list2[0].value = 100
print(list1[0].value) # 输出100
print(list2[0].value,list2[1].value) # 输出100 100
结论:将数乘替换成列表推导式
比如创建一个10*10的列表,每个元素都是0,可以这么写:
ls = [[0] * 10 for i in range(10)]