W grę wchodzą dwie rzeczy:
1. class attributes and instance attributes
2. difference between the operators + and += for lists
+operator wywołuje __add__metodę z listy. Pobiera wszystkie elementy ze swoich operandów i tworzy nową listę zawierającą te elementy, zachowując ich kolejność.
+=__iadd__metoda wywołania operatora na liście. Pobiera iterowalne i dołącza wszystkie elementy iterowalne do listy w miejscu. Nie tworzy nowego obiektu listy.
W klasie fooinstrukcja self.bar += [x]nie jest instrukcją przypisania, ale w rzeczywistości jest tłumaczeniem
self.bar.__iadd__([x]) # modifies the class attribute
który modyfikuje listę w miejscu i działa jak metoda list extend.
W klasie foo2wręcz przeciwnie, instrukcja przypisania w initmetodzie
self.bar = self.bar + [x]
można zdekonstruować jako:
Instancja nie ma atrybutu bar(istnieje jednak atrybut klasy o tej samej nazwie), więc uzyskuje dostęp do atrybutu klasy bari tworzy nową listę, dołączając xdo niej. Oświadczenie przekłada się na:
self.bar = self.bar.__add__([x]) # bar on the lhs is the class attribute
Następnie tworzy atrybut instancji bari przypisuje do niego nowo utworzoną listę. Zauważ, że barprawa strona zadania różni się od barprawej strony.
Dla instancji klasy foo, barjest atrybutem klasy i nie atrybut instancji. W związku z tym każda zmiana atrybutu klasy barzostanie odzwierciedlona we wszystkich instancjach.
Wręcz przeciwnie, każda instancja klasy foo2ma swój własny atrybut instancji, barktóry różni się od atrybutu klasy o tej samej nazwie bar.
f = foo2(4)
print f.bar # accessing the instance attribute. prints [4]
print f.__class__.bar # accessing the class attribute. prints []
Mam nadzieję, że to wszystko wyjaśnia.