>>> list1 = []
>>> list2 = list1
>>> list2 += [1]
>>> print list1
[1]
将此与
进行比较>>> list1 = []
>>> list2 = list1
>>> list2 = list2 + [1]
>>> print list1
[]
有没有理由为'+ =' - 操作修改原始列表?
编辑:只是为了让我的问题更清晰
在大多数语言中,我知道'+ =' - 运算符不能以这种方式工作,我想知道它为什么在python中以这种方式设计。
一些例子:
红宝石
irb(main):001:0> l = []
irb(main):002:0> a = l
irb(main):003:0> a += [2]
irb(main):004:0> l
=> []
斯卡拉等。
答案 0 :(得分:10)
由引用存储的Python列表。
这意味着,当您执行list2 = list1
时,您没有复制列表 - 您只是说“list2
指的是同一事物list1
”,即执行list1 = []
时最初创建的列表。
Python指定+=
表示列表的“附加到位”,因为大多数情况下,当您在列表中使用+=
时,这就是您想要做的 - 您通常不会想要在每次添加元素时创建新列表。
因此,当您追加list2
时,“引用同一个对象list1
”,然后从list1
读取,您会看到附加项目,如预期的那样他们俩都指向同一个名单。
但是,对于+
,始终会创建一个新列表,因为修改任意一个操作数没有意义(因为a+b
并不意味着修改{{1} }或a
)。
因此,当您执行b
时,您创建一个新列表,其中包含list2 = list2 + [1]
和list2
指向的原始对象的所有内容,然后说{ {1}}现在引用该新列表。由于它现在引用了与1
不同的列表,因此当您从list2
进行阅读时,您仍会看到原始列表,而不会看到额外的list1
。
答案 1 :(得分:7)
从Python 2.6.4文档,第6.2.1节。 (增强的任务说明)
像
x += 1
这样的扩充分配表达式可以重写为x = x + 1
,以实现类似但不完全相同的效果。在增强版本中,x仅评估一次。此外,如果可能,实际操作就地执行,这意味着不是创建新对象并将其分配给目标,而是修改旧对象。
[强调补充]
答案 2 :(得分:5)
请参阅documentation regarding Emulating numeric types,其中介绍了实现此行为的方法。这也适用于列表:
调用这些方法来实现增强算术赋值(
+=, -=, *=, /=, //=, %=, **=, <<=, >>=, &=, ^=, |=
)。 这些方法应该尝试就地执行操作(修改self
)并返回结果(可能是,但不一定是self
)。如果未定义特定方法,则扩充分配将回退到常规方法。例如,要执行语句x += y
,其中x
是具有__iadd__()
方法的类的实例,则调用x.__iadd__(y)
。如果x
是未定义__iadd__()
方法的类的实例,则会考虑x.__add__(y)
和y.__radd__(x)
,与x + y
的评估一样。< / p>
答案 3 :(得分:4)
执行list2 += [1]
时,您正在修改列表。这就是为什么你不改变列表指向的引用,但你直接更改列表。当您执行list2 = list2 + [1]
时,您将创建一个新列表。
>>> l = []
>>> id(l)
41523720L
>>> l += [3]
>>> id(l)
41523720L # same as l = []
>>> l = l+[3]
>>> id(l)
41532232L
这解释了差异。
答案 4 :(得分:2)
好吧,因为它是如何运作的。当您编写list2 = list2 + [1]
时,您创建新列表并将其绑定到list2
名称。当您使用+=
时,操作“就地”发生。因此,当list1
和list2
引用相同的对象时(例如此处),您可以使用+=
运算符对其进行修改。
答案 5 :(得分:0)
+=
应该如何运作。一般来说,
a += b
装置
a = a + b
但您的特定情况有不同的问题。当你写
list2 = list1
没有复制品; list2
现在是对同一列表的引用。对list2
的任何修改都会在list1
中显示,反之亦然。
在您的第二个代码段中,list2 + [1]
构建一个新列表,该列表随后会分配给list2
。由于此副本独立于list1
,因此list1
无法更改。
(Nitpicker的角落:使用运算符重载, 可以构造一个对+=
行为不同的类。不要。只是......不要。)
答案 6 :(得分:0)
在python中,你认为变量名在大多数情况下更类似于指针; “=”不复制对象,它将新名称绑定到该对象(在其他上下文中“按引用复制”)。所以list2 = list1
意味着这两个名称都指向相同的列表,而不仅仅是相同列表的两个副本。因此,“+ =”修改两个名称所指向的单个列表。
您可以逐个元素(list2 = [i for in list1]
)或使用copy
模块(list2 = copy.copy(list1)
)