5

我正在学习 Python,并且一直在尝试制作双端队列。但是,我得到不正确的输出,我不知道为什么。我的代码如下:

p = [2, 1], [1, 1]
init_q= deque()

init_q.append(p)
for i in range(len(p)):
    for j in range(len(p[i])):
        temp = p[i][j]
        p[i][j] = 0
        init_q.append(p)
        p[i][j] = temp

while init_q:
    print init_q.pop()

在这段代码中,我输入了一个列表,然后我想创建一个包含 5 个列表的队列,其中 4 个在不同位置有一个 0,我想要的结果是:

([2, 1], [1, 1])
([0, 1], [1, 1])
([2, 0], [1, 1])
([2, 1], [0, 1])
([2, 1], [1, 0])

但是,我得到的结果是:

([2, 1], [1, 1])
([2, 1], [1, 1])
([2, 1], [1, 1])
([2, 1], [1, 1])
([2, 1], [1, 1])
4

3 回答 3

4

您将一个对象放入双端队列,然后更改该对象。事实上,你总是将同一个对象放入双端队列,所以所有双端队列都是对一个对象 p 的引用。

于 2013-01-07T03:29:23.133 回答
3

我通过简化您的代码在 Python Tutor 上创建了一个可视化。摆弄一下,你可以很容易地看到发生了什么。

对代码进行单行更改即可解决此问题。

init_q.append(map(list, p))    # Initialize a new list from p's element lists

这是使用上述更改的可视化。

于 2013-01-07T06:59:15.273 回答
1

跟进我对 Ned Batchelder 的回答的评论,以下是你如何可以不变地做同样的事情:

for i in range(len(p)):
    for j in range(len(p[i])):
        temprow = [0 if y==j else p[i][y] for y in range(len(p[i]))]
        temp = [temprow if x==i else p[x] for x in range(len(p))]
        init_q.append(temp)

在这种情况下,我认为结果比他的建议可读性差很多:

        temp = copy.deepcopy(p)
        temp[i][j] = 0
        init_q.append(temp)

正如我所说,有时它使事情变得更简单,有时不那么简单……但关键是它更容易推理。您不必担心是否有多个lists init_q——或者更糟糕的是,list这些lists 中的子程序——是否共享身份。

权衡是否值得实际上是逐案决定,并且可能对每个程序员都不同。在这种情况下,我不会使用不可变的解决方案,而且我怀疑许多其他 (Python) 程序员会使用。但值得知道如何编写它。

您也可以考虑将其写为 3D 列表,而不是 2D 列表的双端队列,然后将其输入到deque. 它显然是等价的,但从概念上讲,这样想可能更简单:

init_q.append(p)
q = [copy.deepcopy(p) for i in range(len(p)) for j in range(len(p[i]))]
for i in range(len(p)):
    for j in range(len(p[i])):
        q[i*len(p[i])+j][i][j] = 0
init_q.extend(q)

PS,如果你经常做这种事情,你可能想看看numpy. 如果这是你的全部问题,那对你没有任何好处……但如果你用多维数组做任何更复杂的事情,它会的。

于 2013-01-07T04:50:46.577 回答