列表推导式是常见的生成方式,同时[]*N也是快速生成多种元素的快捷方式。
例如以下两种生成方式:
a=[[0]*5]*5
b=[[0 for _ in range(5)] for _ in range(5)]
生成的初始矩阵都是5*5的0矩阵:
[
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]
]
但是真正对其中的元素进行赋值之后就会发现问题:
a[0][0]=2
b[0][0]=2
# a的输出
[
[2, 0, 0, 0, 0],
[2, 0, 0, 0, 0],
[2, 0, 0, 0, 0],
[2, 0, 0, 0, 0],
[2, 0, 0, 0, 0]
]
# b的输出
[
[2, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]
]
可以看出[]*N的方式生成的时候其实实现的是浅拷贝,而列表推导式则是完全开辟新的空间,因此对b的元素赋值之后不会相互影响。接着再使用id()验证一下我们的想法:
a=[[0]*5]*5
a[0][0]=2
b=[[0 for _ in range(5)] for _ in range(5)]
b[0][0]=2
if a[0] is a[1]:
print('a[0] id is ',id(a[0]))
print('a[1] id is ', id(a[1]))
print('a是浅拷贝')
print('-' * 50)
else:
print('a[0] id is ',id(a[0]))
print('a[1] id is ', id(a[1]))
print('a不是浅拷贝')
print('-' * 50)
if a[0][0] is a[1][0]:
print('a[0][0] id is ',id(a[0][0]))
print('a[1][0] id is ', id(a[1][0]))
print('a是浅拷贝')
print('-' * 50)
else:
print('a[0][0] id is ',id(a[0][0]))
print('a[1][0] id is ', id(a[1][0]))
print('-'*50)
if b[0] is b[1]:
print('b[0] id is ',id(b[0]))
print('b[1] id is ', id(b[1]))
print('a是浅拷贝')
print('-' * 50)
else:
print('b[0] id is ',id(b[0]))
print('b[1] id is ', id(b[1]))
print('b不是浅拷贝')
print('-' * 50)
if b[0][0] is b[1][0]:
print('b[0][0] id is ',id(b[0][0]))
print('b[1][0] id is ', id(b[1][0]))
print('b是浅拷贝')
print('-' * 50)
else:
print('b[0][0] id is ',id(b[0][0]))
print('b[1][0] id is ', id(b[1][0]))
print('b不是浅拷贝')
print('-' * 50)
输出如下:
a[0] id is 2248332523272
a[1] id is 2248332523272
a是浅拷贝
--------------------------------------------------
a[0][0] id is 140712520688048
a[1][0] id is 140712520688048
a是浅拷贝
--------------------------------------------------
b[0] id is 2248332530312
b[1] id is 2248332530056
b不是浅拷贝
--------------------------------------------------
b[0][0] id is 140712520688048
b[1][0] id is 140712520687984
b不是浅拷贝
--------------------------------------------------
由此验证了我们的想法,正因为这样的拷贝原因,因而在使用的时候最好采用列表推导式,而不是简单地[]*N的方法