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, foo
l'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 init
mé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 bar
et 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 bar
et lui affecte la liste nouvellement créée. Notez que bar
sur le rhs de l'affectation est différent du bar
sur le lhs.
Pour les instances de classe foo
, bar
est un attribut de classe et non un attribut d'instance. Par conséquent, toute modification de l'attribut de classe bar
sera reflétée pour toutes les instances.
Au contraire, chaque instance de la classe foo2
a son propre attribut d'instance bar
qui 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.