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 foo
l'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 init
metodo
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 bar
e crea un nuovo elenco aggiungendolo x
ad 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 bar
e gli assegna l'elenco appena creato. Nota che bar
a destra dell'assegnazione è diverso da bar
a 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 bar
verrà riflessa per tutte le istanze.
Al contrario, ogni istanza della classe foo2
ha il proprio attributo di istanza bar
che è 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.