Hay dos cosas involucradas aquí:
1. class attributes and instance attributes
2. difference between the operators + and += for lists
+
el operador llama al __add__
método en una lista. Toma todos los elementos de sus operandos y crea una nueva lista que contiene esos elementos manteniendo su orden.
+=
el operador llama al __iadd__
método en la lista. Toma un iterable y agrega todos los elementos del iterable a la lista en su lugar. No crea un nuevo objeto de lista.
En clase, foo
la declaración self.bar += [x]
no es una declaración de asignación, sino que en realidad se traduce en
self.bar.__iadd__([x]) # modifies the class attribute
que modifica la lista en su lugar y actúa como el método de lista extend
.
En clase foo2
, por el contrario, la declaración de asignación en el init
método
self.bar = self.bar + [x]
se puede deconstruir como:
La instancia no tiene atributo bar
(aunque hay un atributo de clase con el mismo nombre) por lo que accede al atributo de clase bar
y crea una nueva lista añadiéndola x
. La declaración se traduce en:
self.bar = self.bar.__add__([x]) # bar on the lhs is the class attribute
Luego crea un atributo de instancia bar
y le asigna la lista recién creada. Tenga bar
en cuenta que en el lado derecho de la asignación es diferente del lado derecho bar
.
Para instancias de clase foo
, bar
es un atributo de clase y no un atributo de instancia. Por lo tanto, cualquier cambio en el atributo de clase bar
se reflejará en todas las instancias.
Por el contrario, cada instancia de la clase foo2
tiene su propio atributo de instancia bar
que es diferente del atributo de clase del mismo nombre bar
.
f = foo2(4)
print f.bar # accessing the instance attribute. prints [4]
print f.__class__.bar # accessing the class attribute. prints []
Espero que esto aclare las cosas.