与Python中的切片相关的代码中的逻辑错误

时间:2016-12-20 22:41:40

标签: python algorithm python-3.x recursion

考虑以下代码片段,生成数组大小为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保持相同列表有关。我似乎无法理解为什么这是一个问题。

1 个答案:

答案 0 :(得分:4)

我一开始并没有注意到你的函数是递归的(应该更好地阅读你的标签)。

你是对的,功能上两者差不多相同。这是完全相同的事情:

# del partial_combination[-1]                     # working (mutate)
# partial_combination = partial_combination[:-1]  # different (rebind)
partial_combination[:] = partial_combination[:-1] # same (mutate)

上述每一项的结果都是您最终得到一个包含相同元素的列表。但是,当delpartial_combination[:] mutate 原始列表时,中间的将名称重新绑定到具有相同元素的新列表。当您将此新列表传递到下一个递归步骤时,它将在其自己的副本上运行,而不是在先前的递归级别正在处理的单个列表上运行。

为了证明这一点,您可以在上述每个选项之后调用print(id(partial_combination)),并查看重新绑定案例中的id更改,而在整个变更案例中保持不变。