为何近乎相同的Python代码执行后freq变量结果差异巨大?
top1与top2函数freq输出差异的原因分析
问题描述
我需要验证合理性:top1与top2函数代码近乎一致,但执行后freq变量的输出内容却存在显著差异。请问原因是什么?我忽略了哪些细节?
代码与执行输出
测试代码
def top1(nums, k): count = {} for i in nums: if i not in count: count[i] = 1 else: count[i] += 1 freq = (len(nums) + 1) * [[]] print('count', count) print('freq', freq) for n, c in count.items(): freq[c].append(n) print('freq', freq) def top2(nums, k): count = {} for n in nums: count[n] = 1 + count.get(n, 0) freq = [[] for i in range(len(nums) + 1)] print('count', count) print('freq', freq) for n, c in count.items(): freq[c].append(n) print('freq', freq) top1([1], 1) print() top2([1], 1)
执行输出
count {1: 1} freq [[], []] freq [[1], [1]] count {1: 1} freq [[], []] freq [[], [1]]
原因分析
核心问题出在**freq列表的初始化方式**上,这是你忽略的关键细节:
top1的初始化方式:
(len(nums)+1)*[[]]
这种写法会先创建一个空列表[],然后将这个列表的引用重复多次填充到新列表中。也就是说,freq里的所有元素指向的是同一个列表对象。当你对freq[1].append(1)进行操作时,本质是修改了那个唯一的列表,所以freq中所有位置的元素都会同步显示这个修改结果。
针对测试用例,len(nums)=1,freq包含2个元素,这两个元素都是同一个空列表的引用。执行append操作后,这个唯一的列表变成[1],因此freq[0]和freq[1]都会显示为[1],最终输出[[1], [1]]。top2的初始化方式:
[[] for i in range(len(nums)+1)]
列表推导式会在每次循环中新建一个独立的空列表,所以freq中的每个元素都是互不关联的独立对象。对freq[1].append(1)操作时,只会修改索引为1的那个列表,其他位置的列表不受影响,最终输出[[], [1]]。
简单来说,Python中用*复制可变对象时,复制的是引用而非新对象;而列表推导式会为每个元素创建新的独立对象,这就是两个函数输出差异的根本原因。
内容的提问来源于stack exchange,提问作者croatoan
相关产品推荐
相关产品推荐

