这里的第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']]
有人可以指出原因吗?感谢。
答案 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。这些不能被更改,只能被替换,因此对一个对象的引用数量并不重要,因为如果想要在一个地方更改对象,则必须重新构建一个对象并替换该引用。其他引用继续指向同一个对象,因此不会更改。