考虑以下代码片段,生成数组大小为k的所有子集[1,2,3,...,n]:
def combinations(n, k):
result = []
directed_combinations(n, k, 1, [], result)
return result
def directed_combinations(n, k, offset, partial_combination, result):
if len(partial_combination) == k:
new_partial = [x for x in partial_combination]
result.append(new_partial)
return
num_remaining = k - len(partial_combination)
i = offset
# kind of checks if expected num remaining is no greater than actual num remaining
while i <= n and num_remaining <= n - i + 1:
partial_combination.append(i)
directed_combinations(n, k, i + 1, partial_combination, result)
del partial_combination[-1]
# partial_combination = partial_combination[:-1] <-- same funcationality as line above, but produces weird bug.
i += 1
print(combinations(n=4,k=2))
例如,combinations(n=4,k=2)
将生成长度为[1,2,3,4]的所有子集。
代码中有两行生成一个列表,其中删除了最后一个元素。我尝试用del
完成它并通过切掉最后一个元素(即[-1]
)来创建一个全新的列表。 del
版本生成正确的结果。但是,[-1]
的版本没有。没有运行时错误;只是一个逻辑错误(即不正确的结果)。
我怀疑这与在切片时创建新列表与使用del
保持相同列表有关。我似乎无法理解为什么这是一个问题。
答案 0 :(得分:4)
我一开始并没有注意到你的函数是递归的(应该更好地阅读你的标签)。
你是对的,功能上两者差不多相同。这是完全相同的事情:
# del partial_combination[-1] # working (mutate)
# partial_combination = partial_combination[:-1] # different (rebind)
partial_combination[:] = partial_combination[:-1] # same (mutate)
上述每一项的结果都是您最终得到一个包含相同元素的列表。但是,当del
和partial_combination[:]
mutate 原始列表时,中间的将名称重新绑定到具有相同元素的新列表。当您将此新列表传递到下一个递归步骤时,它将在其自己的副本上运行,而不是在先前的递归级别正在处理的单个列表上运行。
为了证明这一点,您可以在上述每个选项之后调用print(id(partial_combination))
,并查看重新绑定案例中的id
更改,而在整个变更案例中保持不变。