python中[[]] * (n)和[[] for _ in range(n)]的区别

1、现象

刷leetcode207的时候碰到一个坑,用[[]] * (n)初始化二维数组,逻辑是正确的,但是结果始终不对。

2、原因

最后定位是初始化语句使用错误导致的,我使用的是[[]] * (n),应该使用[[] for _ in range(n)]

3、解释

[[]] * (n)和[[] for _ in range(n)]打印结果完全一样,但是原理却不一样

[[]] * (n)表示复制子列表( 此处为[] ) n次,这些子列表指向或引用相同的对象,也就是内存地址一样,因此修改其中一个子列表元素,会同时影响其他子列表的值,如下面代码中的L1

[[] for _ in range(n)] 表示列表的子列表元素是每次for循环创建的新对象,这些子列表指向或引用不同的对象,内存地址当然也不一样,因此修改其中一个子列表元素,不会影响其他子列表的值,如下面代码中的L2

n = 2
L1 = [[]] * n
L2 = [[] for _ in range(n)]
print(f'L1:{L1}, L2:{L2}')
print(L2 == L2)   #值相等
print(id(L1[0]),id(L1[1])) # L1列表内的元素,地址相同
print(id(L2[0]),id(L2[1])) # L2列表内的元素,地址不同
L1[0].append(1)
L2[0].append(1)
print(f'L1:{L1}, L2:{L2}')

打印结果:

python中[[]] * (n)和[[] for _ in range(n)]的区别_第1张图片

4、注意

L1 中的元素是列表,是可变对象,使用*n复制,不同元素才会指向同一个对象,但是如果L1中元素是不可变对象,比如int、string、float、tuple,使用*n复制的时候,不同元素也会指向同一个元素,但是修改时,由于是不可变对象,修改时会重新开辟一块内存,变量指向新地址,这样修改其中一个元素,不会影响其他元素

i = 2
L1 = [2] * i   # 列表元素为不可变对象 int
print(L1)
print(id(L1[0]),id(L1[1]))
L1[0] = 4
print(id(L1[0]),id(L1[1]))
print(L1)

打印结果为

python中[[]] * (n)和[[] for _ in range(n)]的区别_第2张图片

python中[[]] * (n)和[[] for _ in range(n)]的区别_第3张图片

5、其他

可变数据类型:列表list[ ]、字典dict{ }

不可变数据类型:整型int、字符串str' '、元组tuple()浮点数float

你可能感兴趣的:(python,python,leetcode207)