Existem duas coisas envolvidas aqui:
1. class attributes and instance attributes
2. difference between the operators + and += for lists
+
operador chama o __add__
método em uma lista. Ele pega todos os elementos de seus operandos e faz uma nova lista contendo esses elementos mantendo sua ordem.
+=
o operador chama o __iadd__
método da lista. Ele pega um iterável e anexa todos os elementos do iterável à lista no local. Ele não cria um novo objeto de lista.
Na aula, foo
a declaração self.bar += [x]
não é uma declaração de atribuição, mas na verdade se traduz em
self.bar.__iadd__([x]) # modifies the class attribute
que modifica a lista no local e atua como o método de lista extend
.
Na aula foo2
, ao contrário, a instrução de atribuição no init
método
self.bar = self.bar + [x]
pode ser desconstruída como:
A instância não tem nenhum atributo bar
(embora haja um atributo de classe com o mesmo nome), portanto, ela acessa o atributo de classe bar
e cria uma nova lista anexando x
a ela. A declaração se traduz em:
self.bar = self.bar.__add__([x]) # bar on the lhs is the class attribute
Em seguida, ele cria um atributo de instância bar
e atribui a lista recém-criada a ele. Observe que bar
no rhs da atribuição é diferente do bar
lhs.
Para instâncias de classe foo
, bar
é um atributo de classe e não um atributo de instância. Portanto, qualquer alteração no atributo de classe bar
será refletida em todas as instâncias.
Pelo contrário, cada instância da classe foo2
tem seu próprio atributo de instância, bar
que é diferente do atributo de classe do mesmo nome bar
.
f = foo2(4)
print f.bar # accessing the instance attribute. prints [4]
print f.__class__.bar # accessing the class attribute. prints []
Espero que isso esclareça as coisas.