python中奇怪的列表行为

时间:2013-08-15 23:07:35

标签: python python-3.x

qtd_packs = 2
size_pack = 16
pasta = []
pasta.append ('packs/krun/')
pasta.append ('packs/parting2/')

for k in range(0, qtd_packs):
    for n in range(1, size_pack+1):
        samples_in.append (pasta[k]+str(n)+'.wav')
    samples.append(samples_in)
    del samples_in[0:len(samples_in)]


print(samples)

我基本上是在samples_in 列表中添加samples,然后删除旧samples_in列表以创建新列表。这将发生2次,如qtd_packs =2。但最后,我得到的是两个空列表:

[[], []]

我在appendsamples_in删除了samples之前删除它。那发生了什么?

谢谢

3 个答案:

答案 0 :(得分:2)

在Python中,列表通过引用传递。将samples_in追加到samples时,Python会将samples_in的引用附加到samples。如果您要将samples_in的副本附加到samples,则可以执行以下操作:

samples.append(samples_in[:])

这有效地创建了samples_in中所有项目的新列表,并将该新列表传递到samples.append()。现在,当您清除samples_in中的项目时,您也不会清除附加到samples的列表中的项目。

另请注意,samples_in[:]相当于samples_in[0:len(samples_in)]

答案 1 :(得分:1)

问题是在此之后:

samples.append(samples_in)

samples中新添加的值不是samples_in的副本,而是完全相同的值。您可以从交互式解释器中看到这一点:

>>> samples_in = [0]
>>> samples = []
>>> samples.append(samples_in)
>>> samples[-1] is samples_in
True
>>> id(samples[-1]), id(samples_in)
(12345678, 12345678)

使用interactive visualizer可能会让您更容易看到正在发生的事情。


因此,当您通过一个名称修改值时,如下所示:

>>> del samples_in[0:len(samples_in)]

通过两个名称可以看到相同的修改:

>>> samples[-1]
[]

一旦你意识到两个名字都指的是同一个值,那就应该是显而易见的了。


作为旁注,del samples_in[:]del samples_in[0:len(samples_in)]完全相同,因为它们已经是切片的默认值。


如果您不希望这两个名称引用相同的值,该怎么办?然后你必须明确地复制。

copy模块具有可以复制(几乎)任何内容的功能,但许多类型都有更简单的方法。例如,samples_in[:]要求一个新列表,它将片段从0复制到结尾(同样,这些是默认值)。所以,如果你这样做了:

>>> samples.append(samples_in[:])

... samples[-1]你会得到一个新值。同样,您可以轻松地测试:

>>> samples[-1], samples_in
([0], [0])
>>> samples[-1] == samples_in
True
>>> samples[-1] is samples_in
False
>>> id(samples[-1]), id(samples_in)
23456789, 12345678

如果你改变了一个值,那么它不会影响另一个 - 毕竟它们是单独的值:

>>> del samples_in[:]
>>> samples[-1], samples_in
([0], [])

然而,在这种情况下,你甚至不需要复制。您遇到问题的唯一原因是您尝试反复使用samples_in。没有理由这样做,如果你每次只创建一个新的samples_in值,问题就不会出现在第一位。而不是:

samples_in = []
for k in range(0, qtd_packs):
    for n in range(1, size_pack+1):
        samples_in.append (pasta[k]+str(n)+'.wav')
    samples.append(samples_in)
    del samples_in[0:len(samples_in)]

这样做:

for k in range(0, qtd_packs):
    samples_in = []
    for n in range(1, size_pack+1):
        samples_in.append (pasta[k]+str(n)+'.wav')
    samples.append(samples_in)

答案 2 :(得分:0)

如果你想让样本包含两个列表,下面的beetea答案提供了解决方案,每个列表都包含两个qtd_packs之一的字符串:

qtd_packs = 2
size_pack = 16

pasta = []
pasta.append ('packs/krun/')
pasta.append ('packs/parting2/')

samples = []
samples_in = []
for k in range(0, qtd_packs):
    for n in range(1, size_pack+1):
        samples_in.append (pasta[k]+str(n)+'.wav')
    samples.append(samples_in[:])
    del samples_in[0:len(samples_in)]

print(samples)

生成此输出:

[['packs/krun/1.wav', 'packs/krun/2.wav', 'packs/krun/3.wav', 'packs/krun/4.wav',
'packs/krun/5.wav', 'packs/krun/6.wav', 'packs/krun/7.wav', 'packs/krun/8.wav',
'packs/krun/9.wav', 'packs/krun/10.wav', 'packs/krun/11.wav', 'packs/krun/12.wav',
'packs/krun/13.wav', 'packs/krun/14.wav', 'packs/krun/15.wav', 'packs/krun/16.wav'],
['packs/parting2/1.wav', 'packs/parting2/2.wav', 'packs/parting2/3.wav',
'packs/parting2/4.wav', 'packs/parting2/5.wav', 'packs/parting2/6.wav',
'packs/parting2/7.wav', 'packs/parting2/8.wav', 'packs/parting2/9.wav',
'packs/parting2/10.wav', 'packs/parting2/11.wav', 'packs/parting2/12.wav',
'packs/parting2/13.wav', 'packs/parting2/14.wav', 'packs/parting2/15.wav',
'packs/parting2/16.wav']]

现在,当我最初阅读您的问题时,我认为您正在尝试制作包含所有字符串的单个列表。在那种情况下,您可以使用

samples.extend(samples_in)

而不是

samples.append(samples_in[:])

你会得到一个只包含字符串的平面列表。