创建列表的正确姿势
---
此文并不介绍python中创建列表的各种方式,而源于写基数排序时的一个小Bug
在写基数排序的时候,创建了一个表中表:
1 | a = [[]] * 10 |
这事用来存放对应位数上的元素的。在append
元素的时候发现所有子列表是一起变化的。很自然的想到子列表是共用同一个地址的。查看一下内存地址果然如此。
1 | a = [[]] * 10 |
不用理会在内存中的具体地址是多少,只需要知道每一个列表的地址是一样的就可以了。列表的对应关系如下图所示。
我们知道,在python
中给列表赋值有直接赋值(添加一个地址指针)和拷贝赋值(copy)等方式。
1 | a = [1,2,3] |
在上面的例子中,b和a变量指向的内存地址是一样的,改变a或b的值另外一个也会相应的变化,而c则是独立出来的新变量,c的值与ab的值之间不会相互影响,他们的关系如下:
采用a = [[]] * 10
这种方式创建10个子空列表相当于将一个空列表复制十遍但是指向地址还是同一个,所以改变其中一个子列表的值其他子列表的值相应的发生改变。
那么正确的创建方式是什么呢。亲测使用[[] for _ in range(10)]
可以创建相互独立的子列表。此方式在创建的时候每一次循环都单独生成一个新的地址空间上的列表来添加进原来的列表中。可以查看他们的内存地址:
1 | a = [[] for _ in range(10)] |
可以看到,这种方式创建出来的列表的地址空间是完全不一样的,结构如下:
当然,如果采用循环对同一个变量进行创建,那么它的地址任然是一样的:
1 | x = [] |