2

奇怪的问题,第 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']]

有人可以指出为什么吗?谢谢。

4

3 回答 3

4

因为将列表乘以 int 会创建浅拷贝,而不是深拷贝

Python 不会为大多数事情制作深拷贝,除非您明确告诉它这样做,因为深拷贝与对象一起工作的方式,这可能会使它们复制太多东西,或者最终可能会出现自引用问题。

Python 在deepcopy中有一种处理方法,但是,对于用户定义的类,您需要自己实现该方法。为了避免所有这些麻烦,在您的示例中隐式复制可变对象(例如列表)时,会进行浅拷贝。

于 2013-09-06T02:40:06.600 回答
2

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

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

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

于 2013-09-06T10:29:25.953 回答
0

您所期望的,以及一些中级到经验丰富的程序员可能仍会不时放弃的是,

l = [some_object] * 3

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

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

[create_some_object for _ in range(3)]

在列表的情况下,它很简单:[ [] for _ in range(3)].

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

于 2013-09-06T13:07:07.353 回答