在Python中为何选择就地进行列表增强赋值(+=)?
>>> list1 = []
>>> list2 = list1
>>> list2 += [1]
>>> print list1
[1]
把这个和
>>> list1 = []
>>> list2 = list1
>>> list2 = list2 + [1]
>>> print list1
[]
有没有什么原因导致'+='这个操作会修改原来的列表?
编辑:为了让我的问题更清楚一些
在我知道的大多数编程语言中,'+='这个操作符并不是这样工作的,我想知道为什么在Python中会设计成这样。
一些例子:
Ruby
irb(main):001:0> l = []
irb(main):002:0> a = l
irb(main):003:0> a += [2]
irb(main):004:0> l
=> []
Scala等等。
7 个回答
在文档中查看关于模拟数字类型的内容,这里描述了实现这种行为的方法。这同样适用于列表:
这些方法是用来实现增强的算术赋值操作(比如
+=, -=, *=, /=, //=, %=, **=, <<=, >>=, &=, ^=, |=
)。这些方法应该尝试在原地进行操作(也就是直接修改self
),并返回结果(这个结果可以是self
,但不一定非得是)。如果某个特定的方法没有定义,那么增强赋值就会退回到普通的方法。例如,要执行语句x += y
,假设x
是一个有__iadd__()
方法的类的实例,那么就会调用x.__iadd__(y)
。如果x
是一个没有定义__iadd__()
方法的类的实例,那么就会考虑x.__add__(y)
和y.__radd__(x)
,这和计算x + y
是一样的。
在Python中,列表是通过引用来存储的。
这意味着当你写 list2 = list1
的时候,你并不是在复制这个列表,而是在说 "list2
指向和 list1
一样的东西",也就是你最开始创建的那个列表,比如你写 list1 = []
的时候。
Python中用 +=
来表示“就地添加”这个意思,因为大多数时候你在列表上使用 +=
,其实就是想要这样做——你通常不想每次添加一个元素时都创建一个新列表。
所以,当你往 list2
添加内容时,list2
和 list1
指向的是同一个列表,这样你再去查看 list1
的时候,就能看到你刚添加的内容,因为它们指向的是同一个列表。
但是,使用 +
的时候,总是会创建一个新列表,因为这样做不涉及修改原来的任何一个列表(因为 a+b
并不意味着要修改 a
或 b
)。
因此,当你写 list2 = list2 + [1]
的时候,你实际上是创建了一个新列表,这个新列表包含了 list2
原来指向的所有内容,还有 1
,然后你让 list2
现在指向这个新列表。因为现在 list2
指向的是一个和 list1
不同的列表,所以当你去查看 list1
的时候,依然能看到原来的列表,没有那个额外的 1
。
来自Python 2.6.4文档的第6.2.1节(增强赋值语句)
像
x += 1
这样的增强赋值表达式,可以写成x = x + 1
,虽然效果相似,但并不完全相同。在增强版本中,x 只会被计算一次。而且,当有可能的时候,实际的操作是在原地进行的,这意味着不是创建一个新对象然后把它赋值给目标,而是直接修改旧的对象。
[强调部分]