为什么列表以这种方式运行python?

时间:2013-09-06 02:24:41

标签: python list

这里的第6行和第11行的奇怪问题很奇怪,我不能弄明白为什么?

1 l1 = ['a', 'b', 'c']
2 
3 l2 = [[]] * 3
4 for i in xrange(0, len(l1)):
5     l2[i%len(l1)].extend(l1[i]) # look! not [li[i]] here
6 print 'l2: ', l2  # problem is here
7 
8 l3 = [[]] * 3
9 for i in xrange(0, len(l1)):
10     l3[i%len(l1)].extend([l1[i]]) 
11 print 'l3: ', l3
12 
13 l4 = [[]] * 3
14 for i in xrange(0, len(l1)):
15     if l4[i%len(l1)] == []:
16         l4[i%len(l1)] = [l1[i]]
17     else:
18         l4[i%len(l1)].extend([l1[i]])
19 print 'l4: ', l4

输出打击:

l2:  [['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c']]
l3:  [['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c']]
l4:  [['a'], ['b'], ['c']]

有人可以指出原因吗?感谢。

3 个答案:

答案 0 :(得分:4)

因为将列表乘以int会创建shallow copy,而不是deep copy

Python不会为大多数事情制作深层副本,除非你明确告诉它这样做是因为深层副本使用对象的方式,这可能会使它们复制太多东西,或者最终会出现自我问题引用。

Python有一种方法可以在deepcopy中处理它,但是,对于用户定义的类,您需要自己实现该方法。为了避免所有这些麻烦,在复制可变对象(例如列表)时,就像在您的示例中一样,可以生成浅层副本。

答案 1 :(得分:2)

第5行的工作方式与第10行相同,因为字符串也是一系列字符。例如:

list('abc') == ['a', 'b', 'c']
list('a')   == ['a']

在这种情况下,.extend('a')有效,因为字符串'a'被视为一个字符的序列,再次为'a'。但请尝试比较.extend('abc').extend(['abc']),看看它们不相同。 (第一个给出了意想不到的结果,所以我不建议使用它。)

答案 2 :(得分:0)

您期望的是,有些中级经验丰富的程序员可能会不时出现这种情况,

l = [some_object] * 3

创建some_object副本。但是,在python中,这只会复制对该对象的引用,因此实际上在一个列表中有三次完全相同的对象。由于列表是可变的,因此通过一个引用更改对象也会改变您通过其他引用看到的内容。

如果你想创建不同的对象,就像评论中已经提到的那样,你必须这样做:

[create_some_object for _ in range(3)]

如果是列表,则直截了当:[ [] for _ in range(3)]

在某些情况下,人们没有注意到差异,即在处理不可变对象时,例如元组,字符串,整数或NoneType。这些不能被更改,只能被替换,因此对一个对象的引用数量并不重要,因为如果想要在一个地方更改对象,则必须重新构建一个对象并替换该引用。其他引用继续指向同一个对象,因此不会更改。