在python中进行列表扩充赋值(+ =)的动机是什么?

时间:2011-03-09 08:07:39

标签: python

>>> 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
=> []

斯卡拉等。

7 个答案:

答案 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名称。当您使用+=时,操作“就地”发生。因此,当list1list2引用相同的对象时(例如此处),您可以使用+=运算符对其进行修改。

答案 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)

复制列表