编辑: 我在原始示例中粗心大意。该行为不是在我A向自身添加列表时发生的,而是在我向自身添加 包含 列表的列表时A发生的A。请参阅下面的更正示例。
A
我试图理解省略号列表(那些[...]在您具有列表引用本身时出现并出现的列表)在Python 2中的工作方式。
[...]
我特别想知道为什么,如果A是list,A = A + A似乎不同的工作A += A(和A.append(A))。
list
A = A + A
A += A
A.append(A)
也就是说,为什么会得到:
>>> a = [1, 2] >>> a = a + [a] >>> a [1, 2, [1, 2]]
与
>>> a = [1, 2] >>> a += [a] >>> a [1, 2, [...]]
(请注意,这a.append(a)似乎对我很有效,就像后者一样。)
a.append(a)
如果它有助于弄清楚事情,那么也将不胜感激有关此省略号列表现象的任何其他更一般的信息。
编辑:( 以解决您对问题的编辑引起的其他问题):
a = a + b和a += b不一样的操作。前者执行a.__add__(b),后者执行a.__iadd__(b)(“就地添加”)。
a = a + b
a += b
a.__add__(b)
a.__iadd__(b)
两者之间的区别在于,前者始终创建一个新对象(并将名称a重新绑定到该新对象),而后者则就地修改该对象(如果可以,并且可以使用列表,则可以)。
a
为了说明这一点,只需查看对象的地址即可:
>>> a = [1, 2] >>> id(a) 34660104 >>> a = a + [a] >>> id(a) 34657224 >>> id(a[2]) 34660104
“新”a是从头开始构造的,首先从旧列表中获取值a,然后将对旧对象的引用连接到该列表。
与此相比:
>>> a = [1, 2] >>> id(a) 34658632 >>> a += [a] >>> id(a) 34658632 >>> id(a[2]) 34658632
(旧答案,解释循环引用):
考虑一下:
>>> a = [1, 2]; a += a >>> a [1, 2, 1, 2] >>> a = [1, 2]; a.extend(a) >>> a [1, 2, 1, 2] >>> a = [1, 2]; a += [a] >>> a [1, 2, [...]] >>> a = [1, 2]; a.append(a) >>> a [1, 2, [...]]
因此,总结一下第一部分:
对于列表,a += a相当于调用就地a.extend(a)修改a,并添加在a此操作开始时找到的元素的副本。
a += a
a.extend(a)
相反地,a += [a]对应于a.append(a),两者都创建对列表的引用a(即,一个指向在其存储器地址),并添加 其 到列表中。构成所谓的“循环参考”。
a += [a]
如果您要查看此时的内部表示a,它将看起来像这样:
a: Reference to a list object at address 0xDEADBEEF a[0]: Reference to the integer object "1" a[1]: Reference to the integer object "2" a[2]: Reference to the same list object at address 0xDEADBEEF
旧的Python版本(1.5.1之前的版本)不够聪明,无法检测到它,因此,如果执行a print a,则会[1, 2, [1, 2, [1, 2, [1, 2, [1, 2, [1, 2, ...在无限循环中得到等等。从Python 1.5.1开始,解释器会检测到此情况,[1, 2, [...]]而是打印出来。
print a
[1, 2, [1, 2, [1, 2, [1, 2, [1, 2, [1, 2, ...
[1, 2, [...]]