【问题标题】:Logical Bug in the Code Related to Slicing in Python与 Python 中的切片相关的代码中的逻辑错误
【发布时间】:2016-12-21 06:49:31
【问题描述】:

考虑以下代码,它生成数组 [1,2,3,...,n] 的所有大小为 k 的子集:

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] 的所有长度为 2 的子集。 代码中有两行生成一个列表,其中最后一个元素被删除。我尝试使用del 完成它,并通过切掉最后一个元素(即[-1])来创建一个全新的列表。带有del 的版本会产生正确的结果。但是,带有[-1] 的版本没有。没有运行时错误;只是一个逻辑错误(即不正确的结果)。

我怀疑这与在进行切片时创建新列表与使用 del 保持相同列表有关。我似乎无法理解为什么这是一个问题。

【问题讨论】:

    标签: python algorithm python-3.x recursion


    【解决方案1】:

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

    你是对的,两者在功能上几乎是一样的。这是确切相同的事情:

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

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

    为了证明这一点,您可以在上述每个选项之后调用print(id(partial_combination)),并看到id 在重新绑定情况下发生了变化,而在整个变异情况下保持不变。

    【讨论】:

    • 好的。这说得通。然而,起初,我很困惑为什么最后一个选项改变了列表而不是创建一个新的。我以前从未见过切片的分配。检查docs (3.1.3 section) 为我澄清了这一点。
    • @AzaTulepbergenov here's an additional source 了解变异与重新绑定。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-21
    • 1970-01-01
    • 2017-11-15
    • 2022-01-10
    相关资源
    最近更新 更多