说明一下Python中列表乘法生成列表与直接写出列表的不同。
首先说一下需要列表乘法生成列表的情况:
比如,我们初始化一个0列表,我们可以[0]*10,生成一个长度为10的全0列表,这样做没问题
再比如,我们嵌套列表初始化一个矩阵,类似[[],[],[]],我们可以用[[]]*3,但是这里就有问题了。[0]*10与[[]]*3不同之处在于0是不可变对象,[]是可变对象,列表乘法所生成的大列表中小列表之间的关系是引用
用代码来说明一下:
test_list = [[]]*3
print id(test_list[0])
print id(test_list[1])
print id(test_list)
结果:
39440136
39440136
40163400
这意味着,test_list里面每个元素都是id39440136这个列表元素的索引,这样我们就没法实现多个列表分开存储的需求
如果是列表加法和直接写列表的话,列表中每个元素都是独立的对象。
对于列表加法乘法的理解不能像数学上一样,a*b=b个a相加
下面是实际中遇到的这个例子:我想用四个字典分别统计ip四个字段数值出现频数,结果没有意识到列表乘法的这个问题,导致错误
错误例子:
test = ['111.111.111.111', '222.222.222.222']
nums = [{}]*4
for line in test:
ip_nums = map(int, line.split('.'))
for i in range(2):
nums[i][ip_nums[i]] = nums[i].get(ip_nums[i], 0)+1
print nums
输出:
[{222: 4, 111: 4}, {222: 4, 111: 4}, {222: 4, 111: 4}, {222: 4, 111: 4}]
修改后:
test = ['111.111.111.111', '222.222.222.222']
nums = [{}, {}, {}, {}]
for line in test:
ip_nums = map(int, line.split('.'))
for i in range(2):
nums[i][ip_nums[i]] = nums[i].get(ip_nums[i], 0)+1
print nums
输出:
[{222: 1, 111: 1}, {222: 1, 111: 1}, {222: 1, 111: 1}, {222: 1, 111: 1}]