Python列表推导式与列表*操作的等价性及报错咨询
这俩写法看似相同,实则天差地别!
嘿,这个坑我刚学Python的时候也踩过!你完全没搞错,list1 = [[0.00] * 5 for _ in range(5)]和list2 = [[0.00] * 5] * 5根本不等价,只是表面的“值相等”和“numpy形状相同”给你造成了错觉,咱们来掰扯清楚:
核心区别:子列表是独立对象还是同一引用?
- 对于
list1的写法:
列表推导式会在每次循环中新建一个[0.00]*5列表,所以list1里的5个子列表都是完全独立的内存对象。你可以用print(list1[0] is list1[1])验证,结果是False——这说明它们不是同一个东西。 - 对于
list2的写法:[[0.00]*5] *5是把同一个子列表重复引用了5次,list2里的5个元素其实指向内存中的同一个列表。用print(list2[0] is list2[1])验证,结果是True——改其中一个子列表,其他所有子列表都会跟着变!
为什么表面验证会显示“相同”?
print(list1 == list2)返回True:
Python的列表相等性判断是逐元素值比较,这俩列表的每个位置的值都是0.00,所以值层面是相等的,但这和“对象是否相同”是两回事。np.array(list1).shape == np.array(list2).shape返回True:
Numpy在转换数组时只关心数据的结构和值,不会在意原列表内部的引用关系,所以两者都会被转成(5,5)的二维数组,形状自然相同。
为什么list2会触发IndexError?
举个实际场景:假设你在代码中不小心修改了某个子列表,比如执行list2[0].append(1),因为所有子列表都是同一个对象,list2里的5个子列表都会变成长度为6的列表。如果后续代码中存在“子列表长度固定为5”的假设(比如访问list2[1][5]),就会直接触发“索引超出范围”的错误!
而用list1的话,修改list1[0].append(1)只会让第一个子列表变长,其他子列表还是长度5,不会影响后续的索引访问。
总结
以后创建二维(或多维)列表时,一定要用列表推导式的写法(也就是list1的方式),避免用*重复引用的方式,这种隐蔽的引用bug排查起来特别头疼!
内容的提问来源于stack exchange,提问作者daehanmingoo
相关产品推荐
相关产品推荐

