Python list.append 输出值不同于 list.extend
Python list.append output values differ from list.extend
在另一个网站上看到一个关于一段 Python 代码的问题,这个问题让一些人抓狂。这是一段相当小、看起来很简单的代码,所以我查看了它,弄清楚它试图做什么,然后 运行 它在我的本地系统上,并发现了为什么它让最初的提问者发疯.希望这里有人可以帮助我了解发生了什么。
该代码似乎是一个简单的 "ask the user for three values (x,y,z) and a sum (n); iterate all values to find tuples that sum to n, and add those tuples to a list." 解决方案。但它输出的不是所有总和为 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 append/extend 增量的唯一内容似乎与这个问题。
{编辑:环境细节}
此外,运行 这在 Python 2.7.10 和 Python 3.4.3(cygwin,在 Windows 10 主页下)都具有相同的结果。
extend
将参数列表中的项目添加到进行调用的列表对象中。更像是,将对象从一个列表转储到另一个列表而不清空前者。
append
另一方面,只是 appends;而已。因此,将一个列表对象附加到另一个列表,并使用对附加列表的现有引用可能会造成一些损害 - 如本例所示。附加列表后,part
仍然保留对列表的引用(因为您正在修改 到位 ),所以您实际上是在修改和(重新)每次附加相同的列表对象。
您可以通过在 append 案例的每个 parent 迭代开始时构建一个新列表来防止这种情况。
或者简单地附加一份 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
本身。
如果我们更改 part
中的一个元素,我们可以看到这种差异的后果:
In [326]: part[1]=1
In [327]: alist
Out[327]: [[0, 1, 0], 0, 0, 0]
追加part
也变了,但扩展部分没变
这就是为什么您的 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 个指向 part
的指针(不是 3 个副本)。更改其中一个子列表,我们将更改所有子列表,包括 part
.
在另一个网站上看到一个关于一段 Python 代码的问题,这个问题让一些人抓狂。这是一段相当小、看起来很简单的代码,所以我查看了它,弄清楚它试图做什么,然后 运行 它在我的本地系统上,并发现了为什么它让最初的提问者发疯.希望这里有人可以帮助我了解发生了什么。
该代码似乎是一个简单的 "ask the user for three values (x,y,z) and a sum (n); iterate all values to find tuples that sum to n, and add those tuples to a list." 解决方案。但它输出的不是所有总和为 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 append/extend 增量的唯一内容似乎与这个问题。
{编辑:环境细节}
此外,运行 这在 Python 2.7.10 和 Python 3.4.3(cygwin,在 Windows 10 主页下)都具有相同的结果。
extend
将参数列表中的项目添加到进行调用的列表对象中。更像是,将对象从一个列表转储到另一个列表而不清空前者。
append
另一方面,只是 appends;而已。因此,将一个列表对象附加到另一个列表,并使用对附加列表的现有引用可能会造成一些损害 - 如本例所示。附加列表后,part
仍然保留对列表的引用(因为您正在修改 到位 ),所以您实际上是在修改和(重新)每次附加相同的列表对象。
您可以通过在 append 案例的每个 parent 迭代开始时构建一个新列表来防止这种情况。
或者简单地附加一份 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
本身。
如果我们更改 part
中的一个元素,我们可以看到这种差异的后果:
In [326]: part[1]=1
In [327]: alist
Out[327]: [[0, 1, 0], 0, 0, 0]
追加part
也变了,但扩展部分没变
这就是为什么您的 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 个指向 part
的指针(不是 3 个副本)。更改其中一个子列表,我们将更改所有子列表,包括 part
.