1. list对象的*操作符
>>> a = [[1]]*10
>>> a
[[1], [1], [1], [1], [1], [1], [1], [1], [1], [1]]
>>> a[1][0] = 2
>>> a
[[2], [2], [2], [2], [2], [2], [2], [2], [2], [2]]
>>>
也就是说,这10个对象实际上是指向的同一个list对象。
这是bug,还是feature?或者是优化?
总之是蛮让人火大的就是了。
用 a = [[0] for x in range(10)] 这种写法就没有这个问题了。
2. 深拷贝
>>> a = [[0] for x in range(10)]
>>> a
[[0], [0], [0], [0], [0], [0], [0], [0], [0], [0]]
>>> b = list(a)
>>> b
[[0], [0], [0], [0], [0], [0], [0], [0], [0], [0]]
>>> a[1][0] = 2
>>> b
[[0], [2], [0], [0], [0], [0], [0], [0], [0], [0]]
>>>
b = list(a)
意味着a和b中都存放这10个指针。指向[0], [0], [0] .... 这10个对象。
a[1][0] = 2 后 a 自己的值没有改变,改变的是第二个 [0] 对象。
由于 b 也是指向它的,所以打印b的时候会发现这一点。
这个问题是自己经常犯的问题,大多都是debug半天才知道怎么回事。
使用
import copy
b = copy.deepcopy(a)
可以解决这个问题。
3. 如何避免这些问题
要时刻记得,python中的对象就只有两种,mutable和immutable。也就是可改变和不可改变。
immutable的包括:str tuple int ...
mutable可改变的包括:list dict ...
immutable的就是原子的。mutable里面存放的都是指向mutable或者immutable的指针。
调试的时候,可以使用id(obj)获得每个对象的id。这个貌似就是python管理的运行时的对象的地址。
如果发现两个obj的id相同,那他们就是同一个货。。