Strange behaviour when inheriting from a list in p

2019-06-05 21:27发布

问题:

I was fiddling around with inheritance recently and I'm a little confused by the behaviour of the following:

class Foo(list):

    def method(self, thing):
        new = self + [thing]
        print(new)
        self = new
        print(self)

    def method2(self, thing):
        self += [thing]

>>> f = Foo([1, 2, 3, 4, 5])
>>> f.method(10)
[1, 2, 3, 4, 5, 10]
[1, 2, 3, 4, 5, 10]
>>> f
[1, 2, 3, 4, 5]
>>> f.method2(10)
>>> f
[1, 2, 3, 4, 5, 10]

Why does the in-place method method2 work but the first one doesn't?

回答1:

Because that's how in-place operators work.

self = self + [thing] creates a new list and put it into the local variable self, overriding the passed one. But it doesn't modify the object itself. Internally, it does self = self.__add__([thing]).

self += [thing], OTOH, modifies the list in-place. Internally it tries self = self.__iadd__([thing]) first. iadd stands for "inplace add". Only if that doesn't exist, self = self.__add__([thing]) is called.

The difference is that __add__() always creates a new object and leaves the others untouched. __iadd__(), however, is supposed to try first to modify the object it operates on. In this case, it returns it so that no change of object occurs, i. e. self refers to the same object as before. Only if this is not possible, it returns a new one which is then assigned.



回答2:

list.__add__() (the + operator builtin) creates a new list, while list.__iadd__() (the += operator builtin) modifies the list in place.