Python-为什么+ =在列表上表现异常?

发布于 2021-02-02 23:23:04

+=python中的运算符似乎在列表上运行异常。谁能告诉我这是怎么回事?

class foo:  
     bar = []
     def __init__(self,x):
         self.bar += [x]


class foo2:
     bar = []
     def __init__(self,x):
          self.bar = self.bar + [x]

f = foo(1)
g = foo(2)
print f.bar
print g.bar 

f.bar += [3]
print f.bar
print g.bar

f.bar = f.bar + [4]
print f.bar
print g.bar

f = foo2(1)
g = foo2(2)
print f.bar 
print g.bar 

输出值

[1, 2]
[1, 2]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3, 4]
[1, 2, 3]
[1]
[2]

foo += bar似乎影响类的每个实例,而foo = foo + bar似乎以我希望事情表现的方式表现。

该+=运算符称为“化合物赋值运算符”。

关注者
0
被浏览
162
1 个回答
  • 面试哥
    面试哥 2021-02-02
    为面试而生,有面试问题,就找面试哥。

    一般的答案是+=尝试调用__iadd__特殊方法,如果该方法不可用,它将尝试使用__add__替代方法。因此,问题在于这些特殊方法之间的差异。

    __iadd__特殊方法是就地此外,这是它发生变异,它作用于对象。该__add__特殊方法返回一个新的对象,也可用于标准+操作。

    因此,当在+=已__iadd__定义的对象上使用运算符时,该对象将被修改。否则,它将尝试使用纯文本__add__并返回一个新对象。

    这就是为什么对于诸如列表之类的可变类型会+=更改对象的值,而对于诸如元组,字符串和整数之类的不可变类型则会返回一个新对象(a += b等于a = a + b)的原因。

    对于类型的同时支持__iadd__,并__add__因此你必须要小心你使用哪一个。a += b将调用__iadd__和变异a,而a = a + b将创建一个新对象并将其分配给a。他们是不一样的操作!

    >>> a1 = a2 = [1, 2]
    >>> b1 = b2 = [1, 2]
    >>> a1 += [3]          # Uses __iadd__, modifies a1 in-place
    >>> b1 = b1 + [3]      # Uses __add__, creates new list, assigns it to b1
    >>> a2
    [1, 2, 3]              # a1 and a2 are still the same list
    >>> b2
    [1, 2]                 # whereas only b1 was changed
    

    对于不可变的类型(没有__iadd__a += b,a = a + b它们是等效的。这就是让你+=在不可变类型上使用的原因,这似乎是一个奇怪的设计决定,除非你考虑到否则无法+=在数字等不可变类型上使用!



  • 面试哥
    面试哥 2021-02-02
    为面试而生,有面试问题,就找面试哥。

    对于一般情况,请参见Scott Griffith的答案。但是,当像你一样处理列表时,+=运算符是的简写someListObject.extend(iterableObject)。请参阅extend()的文档。

    该extend函数会将参数的所有元素添加到列表中。

    执行此操作时,foo += something你要foo在适当位置修改列表,因此无需更改名称foo指向的引用,而是直接更改列表对象。使用foo = foo + something,你实际上是在创建一个新列表。

    此示例代码将对其进行解释:

    >>> l = []
    >>> id(l)
    13043192
    >>> l += [3]
    >>> id(l)
    13043192
    >>> l = l + [3]
    >>> id(l)
    13059216
    

    请注意,当你将新列表重新分配给时,参考如何变化l。

    与bar使用类变量(而不是实例变量)一样,就地修改将影响该类的所有实例。但是,当重新定义时self.bar,该实例将具有一个单独的实例变量,self.bar而不会影响其他类实例。



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看