Python列表:为什么在连接操作后创建新的列表对象?
我正在浏览学习Python 5E书中关于列表的主题。 我注意到,若我们在列表上进行连接,它会创建新的对象。扩展方法不创建新对象,即就地更改。 在串联的情况下会发生什么 比如说Python列表:为什么在连接操作后创建新的列表对象?,python,python-2.7,python-3.x,Python,Python 2.7,Python 3.x,我正在浏览学习Python 5E书中关于列表的主题。 我注意到,若我们在列表上进行连接,它会创建新的对象。扩展方法不创建新对象,即就地更改。 在串联的情况下会发生什么 比如说 l = [1,2,3,4] m = l l = l + [5,6] print l,m #output ([1,2,3,4,5,6], [1,2,3,4]) 如果我使用如下的增广赋值 l = [1,2,3,4] m = l l += [5,6] print l,m #output ([1,2,3,4,5,6], [1
l = [1,2,3,4]
m = l
l = l + [5,6]
print l,m
#output
([1,2,3,4,5,6], [1,2,3,4])
如果我使用如下的增广赋值
l = [1,2,3,4]
m = l
l += [5,6]
print l,m
#output
([1,2,3,4,5,6], [1,2,3,4,5,6])
在这两种操作的情况下,后台会发生什么情况?在后台使用两种方法:
\uuuuuuuuuuuuuuuuuuu
和\uuuuuuuuuuuuidd
l+[5,6]
是l.\uu添加([5,6])
的快捷方式l
的\uuuuu add\uuuu
方法返回与其他内容相加的结果。因此,l=l+[5,6]
将l
重新分配给添加的l
和[5,6]
。它不会影响m
,因为您没有更改对象,而是重新定义了名称l+=[5,6]
是l.\uu iadd\uuu([5,6])
的快捷方式。在这种情况下,\uuuu iadd\uuu
会更改列表。由于m
引用相同的对象,因此m
也会受到影响
Edit:如果未实现
\uuuu iadd\uuuuuu
,例如使用不可变类型,如tuple
和str
,那么Python将使用\uuuu add\uuuuu
。例如,x+=y
将转换为x=x+y
。此外,在x+y
中,如果x
未实现\uuuu添加
,则将使用y.\uuu radd\uuuuu(x)
(如果可用)。因此x+=y
实际上可能是x=y.\uuu radd\uuuu(x)
背景。通过检查内存中引用的对象,您可以更好地理解这一点。让我们使用
在第一种情况下:
>>> l = [1,2,3,4]
>>> id(l)
4497052232
>>> m = l
>>> id(m)
4497052232
>>> l = l + [5,6]
>>> id(l)
4497052448
>>> print l, id(l), m, id(m)
[1, 2, 3, 4, 5, 6] 4497052448 [1, 2, 3, 4] 4497052232
>>>
请注意,l=l+[5,6]
在内存中创建了一个新对象,并且l
引用了该对象
在第二种情况下:
>>> l = [1,2,3,4]
>>> id(l)
4497052520
>>> m = l
>>> id(m)
4497052520
>>> l += [5,6]
>>> id(l)
4497052520
>>> print l, id(l), m, id(m)
[1, 2, 3, 4, 5, 6] 4497052520 [1, 2, 3, 4, 5, 6] 4497052520
>>>
l+=[5,6]
引用内存中的同一对象。结果就是这样。
因此,基本上,
+=
相当于inplace add 注意这里有一个重要的警告:不可变类型不实现\uuuuuidd\uuuuu
,对于任何具有\uuuuuuadd\uuuuu
但不具有\uuuuidd\uuuuuu
的对象,Python都会使用\uuuuuuadd\uuuuu
来执行操作。因此,对于tuple
s,当你做a=(1,2)
,b=a
,a+=(3,4)
,由于tuple
是不可变的,实际上就好像最后一条语句是a=a+(3,4)
,因为a
被一个全新的tuple
所取代,而b
继续引用原始(1,2)
元组。我喜欢\uuuu radd\uuuu
上的添加。