Why does += behave unexpectedly on lists?

后端 未结 8 1415
春和景丽
春和景丽 2020-11-21 07:20

The += operator in python seems to be operating unexpectedly on lists. Can anyone tell me what is going on here?

class foo:  
     bar = []
            


        
8条回答
  •  没有蜡笔的小新
    2020-11-21 08:13

    There are two things involved here:

    1. class attributes and instance attributes
    2. difference between the operators + and += for lists
    

    + operator calls the __add__ method on a list. It takes all the elements from its operands and makes a new list containing those elements maintaining their order.

    += operator calls __iadd__ method on the list. It takes an iterable and appends all the elements of the iterable to the list in place. It does not create a new list object.

    In class foo the statement self.bar += [x] is not an assignment statement but actually translates to

    self.bar.__iadd__([x])  # modifies the class attribute  
    

    which modifies the list in place and acts like the list method extend.

    In class foo2, on the contrary, the assignment statement in the init method

    self.bar = self.bar + [x]  
    

    can be deconstructed as:
    The instance has no attribute bar (there is a class attribute of the same name, though) so it accesses the class attribute bar and creates a new list by appending x to it. The statement translates to:

    self.bar = self.bar.__add__([x]) # bar on the lhs is the class attribute 
    

    Then it creates an instance attribute bar and assigns the newly created list to it. Note that bar on the rhs of the assignment is different from the bar on the lhs.

    For instances of class foo, bar is a class attribute and not instance attribute. Hence any change to the class attribute bar will be reflected for all instances.

    On the contrary, each instance of the class foo2 has its own instance attribute bar which is different from the class attribute of the same name bar.

    f = foo2(4)
    print f.bar # accessing the instance attribute. prints [4]  
    print f.__class__.bar # accessing the class attribute. prints []  
    

    Hope this clears things.

提交回复
热议问题