Ci sono due cose coinvolte qui:
1. class attributes and instance attributes
2. difference between the operators + and += for lists
+operatore chiama il __add__metodo su un elenco. Prende tutti gli elementi dai suoi operandi e crea un nuovo elenco contenente quegli elementi mantenendo il loro ordine.
+=l'operatore chiama il __iadd__metodo nell'elenco. Richiede un iterabile e aggiunge tutti gli elementi dell'iterabile all'elenco in posizione. Non crea un nuovo oggetto elenco.
In classe fool'istruzione self.bar += [x]non è un'istruzione di assegnazione ma si traduce effettivamente in
self.bar.__iadd__([x]) # modifies the class attribute
che modifica l'elenco in posizione e agisce come il metodo list extend.
In classe foo2, al contrario, l'istruzione di assegnazione nel initmetodo
self.bar = self.bar + [x]
può essere decostruito come:
L'istanza non ha alcun attributo bar(c'è un attributo di classe con lo stesso nome, però) quindi accede all'attributo di classe bare crea un nuovo elenco aggiungendolo xad esso. La dichiarazione si traduce in:
self.bar = self.bar.__add__([x]) # bar on the lhs is the class attribute
Quindi crea un attributo di istanza bare gli assegna l'elenco appena creato. Nota che bara destra dell'assegnazione è diverso da bara sinistra.
Per le istanze di classe foo, barè un attributo di classe e non un attributo di istanza. Pertanto, qualsiasi modifica all'attributo di classe barverrà riflessa per tutte le istanze.
Al contrario, ogni istanza della classe foo2ha il proprio attributo di istanza barche è diverso dall'attributo di classe con lo stesso nome bar.
f = foo2(4)
print f.bar # accessing the instance attribute. prints [4]
print f.__class__.bar # accessing the class attribute. prints []
Spero che questo chiarisca le cose.