【问题标题】:Python list.append output values differ from list.extendPython list.append 输出值与 list.extend 不同
【发布时间】:2017-03-19 15:21:47
【问题描述】:

在另一个网站上看到一个关于一段让某人发疯的 Python 代码的问题。这是一段相当小、看起来很简单的代码,所以我查看了它,弄清楚它想做什么,然后在我的本地系统上运行它,并发现它为什么会让最初的提问者发疯。希望这里的人可以帮助我了解发生了什么。

代码似乎是一个简单的“向用户询问三个值 (x,y,z) 和一个总和 (n);迭代所有值以找到总和为 n 的元组,并将这些元组添加到列表中。 "解决方案。但它输出的不是所有总和为 n 的元组,而是一个元组列表,其计数等于总和为 n 的元组的计数,但其内容都是 "[x,y,z] ”。为了解决这个问题,我将附加调用更改为扩展调用(知道这将取消列出添加的元组),以查看行为是否发生了变化。我希望得到相同的输出,就像 "x,y,z,x,y,z..." 重复,而不是 "[x,y,z],[x,y,z]" 重复,因为当我阅读并理解 Python 文档时,这就是列表中追加和扩展之间的区别。相反,当我使用扩展时,我得到的是总和为 n 的元组的正确值,只是通过扩展打破了它们的元组形式。

问题代码如下:

my = []

x = 3
y = 5
z = 7
n = 11

part = [0,0,0]
for i in range(x+1):
    part[0] = i
    for j in range(y+1):
        part[1] = j
        for k in range(z+1):
            part[2] = k
            if sum(part) == n:
                my.append(part)
print(my)

和输出:

[[3, 5, 7], [3, 5, 7], [3, 5, 7], [3, 5, 7], [3, 5, 7], [3, 5, 7], [3, 5, 7], [3, 5, 7], [3, 5, 7], [3, 5, 7], [3, 5, 7], [3, 5, 7], [3, 5, 7], [3, 5, 7]]

这是扩展输出:

[0, 4, 7, 0, 5, 6, 1, 3, 7, 1, 4, 6, 1, 5, 5, 2, 2, 7, 2, 3, 6, 2, 4, 5, 2, 5, 4, 3, 1, 7, 3, 2, 6, 3, 3, 5, 3, 4, 4, 3, 5, 3]

还有扩展代码:

my = []

x = 3
y = 5
z = 7
n = 11

part = [0,0,0]
for i in range(x+1):
    part[0] = i
    for j in range(y+1):
        part[1] = j
        for k in range(z+1):
            part[2] = k
            if sum(part) == n:
                my.extend(part)
print(my)

我们将不胜感激。我在 Google 和几个问答网站上搜索了一段时间,我发现的关于 Python 附加/扩展增量的唯一内容似乎与此问题没有任何关系。

{编辑:环境细节}

此外,在 Python 2.7.10 和 Python 3.4.3(cygwin,在 Windows 10 home 下)运行此程序,结果相同。

【问题讨论】:

    标签: python list append extend


    【解决方案1】:

    extend 将参数列表中的项目添加到进行调用的列表对象中。更像是在不清空列表的情况下将对象从一个列表转储到另一个列表。

    append 另一方面,只是追加;而已。因此,使用对附加列表的现有引用将列表对象附加到另一个列表可能会造成一些损害 - 就像在这种情况下一样。附加列表后,part 仍然保留对列表的引用(因为您正在修改 ),因此您实际上是在修改和(重新)附加相同的列表对象每次。

    您可以通过在 append 案例的每个 parent 迭代开始时构建一个新列表来防止这种情况发生。

    或者通过简单地附加part 列表的副本:

    my.append(part[:]) 
    my.append(list(part))
    my.append(part.copy())  # Python 3 only
    

    这将追加一个在其新父列表之外没有其他现有引用的列表。

    【讨论】:

    • 谢谢;我没有从文档中理解这种细微差别。理智恢复了! :-)
    • 尝试使用 part.copy 导致“AttributeError: 'list' object has no attribute 'copy'”;做了更多的挖掘,并提出了“my.append(list(part))”,它通过获取当前部分指针的列表而不是附加部分指针本身来解决问题。
    【解决方案2】:

    发生了一些事情 - 追加和扩展之间的区别,以及列表的可变性。

    考虑一个更简单的情况:

    In [320]: part=[0,0,0]
    In [321]: alist=[]
    In [322]: alist.append(part)
    In [323]: alist
    Out[323]: [[0, 0, 0]]  
    

    append 实际上在列表中放置了一个指向part 的指针。

    In [324]: alist.extend(part)
    In [325]: alist
    Out[325]: [[0, 0, 0], 0, 0, 0]
    

    extendpart 的元素放入列表中,而不是part 本身。

    如果我们更改part 中的一个元素,我们可以看到这种差异的后果:

    In [326]: part[1]=1
    In [327]: alist
    Out[327]: [[0, 1, 0], 0, 0, 0]
    

    附加的part 也发生了变化,但扩展部分没有。

    这就是为什么您的append 案例由子列表组成,并且子列表的最终值为part - 因为它们都是part

    extendpart 的当前值放入列表中。它们不仅不是子列表,而且不会随着 part 的变化而变化。

    这是列表指针问题的一个变体:

    In [333]: alist = [part]*3
    In [334]: alist
    Out[334]: [[0, 1, 0], [0, 1, 0], [0, 1, 0]]
    In [335]: alist[0][0]=2
    In [336]: part
    Out[336]: [2, 1, 0]
    In [337]: alist
    Out[337]: [[2, 1, 0], [2, 1, 0], [2, 1, 0]]
    

    alist 包含 3 个指向 part 的指针(不是 3 个副本)。更改其中一个子列表,我们将全部更改,包括 part

    【讨论】:

    • 感谢您的详细解释;现在更有意义了。
    猜你喜欢
    • 1970-01-01
    • 2011-08-01
    • 2022-07-06
    • 1970-01-01
    • 2012-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-16
    相关资源
    最近更新 更多