当我执行(我正在使用交互式shell)这些语句时,我得到了这个:
L=[1,2,3]
K=L
L.append(4)
L
[1,2,3,4]
K
[1,2,3,4]
但是当我用L = L +替换L.append(4)时完全相同的事情[4] 我明白了:
L
[1,2,3,4]
K
[1,2,3]
这是某种参考物吗?为什么会这样?
我注意到的另一个有趣的事情是L + = [4]就像.append,这是奇怪的,因为我认为它会像L = L + [4]。
对所有这些的澄清将不胜感激。
由于
答案 0 :(得分:16)
L.append(4)
这会在现有列表L
的末尾添加一个元素。
L += [4]
+=
运算符调用魔术__iadd__()
方法。结果list
会覆盖__iadd__()
方法,并使其等同于extend()
,与append()
一样,会将元素直接添加到现有列表中。
L = L + [4]
L + [4]
生成一个新列表,该列表等于L
,并在末尾添加了4个。然后将此新列表分配回L
。由于您已创建新的列表对象,因此此作业不会更改K
。
我们可以使用id()
来确定何时创建新的对象引用:
>>> L = [1, 2, 3]
>>> id(L)
152678284
>>> L.append(4)
>>> id(L)
152678284
>>> L = [1, 2, 3]
>>> id(L)
152680524
>>> L = L + [4]
>>> id(L)
152678316
答案 1 :(得分:2)
使用append
,您可以直接修改列表。使用L=L+[4]
,您正在制作原始L
的副本并添加新元素,然后将该结果分配回L
并将其等同于K
。< / p>
我不确定+=
的行为。
答案 2 :(得分:1)
如果您对字节码感到好奇:
>>> def L_app( ):
... L.append( 4 )
...
>>> def L_add( ):
... L = L + [ 4 ]
...
>>> def L_add_inplace( ):
... L += [ 4 ]
...
>>> dis.dis( L_app )
2 0 LOAD_GLOBAL 0 (L)
3 LOAD_ATTR 1 (append)
6 LOAD_CONST 1 (4)
9 CALL_FUNCTION 1
12 POP_TOP
13 LOAD_CONST 0 (None)
16 RETURN_VALUE
>>> dis.dis( L_add )
2 0 LOAD_FAST 0 (L)
3 LOAD_CONST 1 (4)
6 BUILD_LIST 1
9 BINARY_ADD
10 STORE_FAST 0 (L)
13 LOAD_CONST 0 (None)
16 RETURN_VALUE
>>> dis.dis( L_add_inplace )
2 0 LOAD_FAST 0 (L)
3 LOAD_CONST 1 (4)
6 BUILD_LIST 1
9 INPLACE_ADD
10 STORE_FAST 0 (L)
13 LOAD_CONST 0 (None)
16 RETURN_VALUE
答案 3 :(得分:0)
在您的第一个示例中,K
和L
变量名称引用相同的对象,因此当您调用一个方法来改变该对象时,通过两个引用都可以看到更改。在第二个示例中,+
运算符调用list.__add__
,它返回新对象(两个列表的串联),L
名称现在引用此新对象,而{{1} 1}}完好无损。