Python list.append输出值与list.extend不同

Python list.append输出值与list.extend不同,python,list,append,extend,Python,List,Append,Extend,在另一个网站上看到一个关于一段让人发疯的Python代码的问题。这是一段相当小、直观的代码,所以我查看了它,找出了它试图做什么,然后在本地系统上运行,并发现了它为什么会让最初的提问者发疯。希望这里有人能帮我了解发生了什么 代码似乎是一个直截了当的“要求用户提供三个值(x,y,z)和一个和(n);迭代所有值以找到和为n的元组,并将这些元组添加到列表中。”解决方案。但它输出的不是所有和n相加的元组,而是一个元组列表,其计数等于和n相加的元组计数,但其内容都是“[x,y,z]”。为了解决这个问题,我将

在另一个网站上看到一个关于一段让人发疯的Python代码的问题。这是一段相当小、直观的代码,所以我查看了它,找出了它试图做什么,然后在本地系统上运行,并发现了它为什么会让最初的提问者发疯。希望这里有人能帮我了解发生了什么

代码似乎是一个直截了当的“要求用户提供三个值(x,y,z)和一个和(n);迭代所有值以找到和为n的元组,并将这些元组添加到列表中。”解决方案。但它输出的不是所有和n相加的元组,而是一个元组列表,其计数等于和n相加的元组计数,但其内容都是“[x,y,z]”。为了解决这个问题,我将append调用更改为extend调用(知道这将取消列出添加的元组),以查看行为是否发生了变化。我希望得到相同的输出,就像“x,y,z,x,y,z…”一样重复,而不是“[x,y,z],[x,y,z]”重复,因为在阅读和理解Python文档时,这就是在列表上追加和扩展的区别。当我使用extend时,我得到的是求和为n的元组的正确值,只是通过extend从元组形式中分离出来

以下是问题代码:

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附加/扩展增量的唯一内容似乎与这个问题没有任何关联

{编辑:环境详细信息}


另外,在Python2.7.10和Python3.4.3(cygwin,在Windows 10 home下)中运行此操作,结果相同。

extend
将参数列表中的项目添加到发出调用的列表对象。更像是,将对象从一个列表转储到另一个列表,而不清空前者

追加
另一方面,只是追加;没别的了。因此,将一个列表对象附加到另一个列表中,并带有对附加列表的现有引用,可能会造成一些损害,如本例所示。添加列表后,
part
仍然保留对列表的引用(因为您正在原地修改),因此每次都在修改和(重新)添加相同的列表对象

您可以通过在追加案例的每个父迭代开始时构建新列表来防止这种情况

或者只需附加一份
部分
列表:

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

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

有两件事正在发生-附加和扩展之间的区别,以及列表的易变性

考虑一个更简单的情况:

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]
extend
part
的元素放在列表中,而不是
part
本身

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

In [326]: part[1]=1
In [327]: alist
Out[327]: [[0, 1, 0], 0, 0, 0]
追加
部分
也发生了变化,但扩展部分没有发生变化

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

extend
part
的当前值放入列表中。它们不仅不是子列表,而且不会随着
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个指针(不是3个副本)。更改其中一个子列表,我们将更改所有子列表,包括
部分

谢谢;我没有从文件中看出细微差别。恢复理智!:-)尝试使用part.copy导致“AttributeError:“list”对象没有属性“copy”;做了更多的挖掘,并提出了“my.append(list(part))”,它也解决了这个问题,通过获取当前部分指针的列表,而不是附加部分指针本身;现在,这显然更有意义。