Il y a deux choses impliquées ici:
1. class attributes and instance attributes
2. difference between the operators + and += for lists
+L'opérateur appelle la __add__méthode sur une liste. Il prend tous les éléments de ses opérandes et crée une nouvelle liste contenant ces éléments en conservant leur ordre.
+=l'opérateur appelle la __iadd__méthode de la liste. Il prend un itérable et ajoute tous les éléments de l'itérable à la liste en place. Il ne crée pas de nouvel objet de liste.
En classe, fool'instruction self.bar += [x]n'est pas une instruction d'affectation mais se traduit en fait par
self.bar.__iadd__([x]) # modifies the class attribute
qui modifie la liste en place et agit comme la méthode list extend.
En classe foo2, au contraire, l'instruction d'affectation dans la initméthode
self.bar = self.bar + [x]
peut être déconstruite comme suit:
l'instance n'a pas d'attribut bar(il existe cependant un attribut de classe du même nom), donc elle accède à l'attribut de classe baret crée une nouvelle liste en y ajoutant x. La déclaration se traduit par:
self.bar = self.bar.__add__([x]) # bar on the lhs is the class attribute
Ensuite, il crée un attribut d'instance baret lui affecte la liste nouvellement créée. Notez que barsur le rhs de l'affectation est différent du barsur le lhs.
Pour les instances de classe foo, barest un attribut de classe et non un attribut d'instance. Par conséquent, toute modification de l'attribut de classe barsera reflétée pour toutes les instances.
Au contraire, chaque instance de la classe foo2a son propre attribut d'instance barqui est différent de l'attribut de classe du même nom bar.
f = foo2(4)
print f.bar # accessing the instance attribute. prints [4]
print f.__class__.bar # accessing the class attribute. prints []
J'espère que cela clarifie les choses.