Your real problem
Your big problem there is that you’re using a list ([]
) as a standard argument in the method __init__
- like the line def __init__(self,caixa=[]):
is executed only once, this list is created only once, and a single and same list will be used in all instances class f
.
To fix this, change your code to:
class f():
def __init__(self,caixa=None):
self.caixa= caixa if caixa is not None else []
Done - with this change, a new list is created every instance.
(of course the class g
needs the same change in the declaration of __init__
)
This whole "list be the same every time __init__
is called, it may seem strange, but precisely, a characteristic of Python is that it has no "exceptions" - this behavior was less planned, than being a consequence of how the language works. For those who are beginners, you don’t know how it actually works - the "def" command that creates functions is executed when a file . py is imported - executing the "def" command creates a "Function" object which is an instance of "Functiontype". One of the attributes of a Function is its code. Another of the attributes is the standard arguments - the object placed as the default argument becomes an attribute of the Function and is the same in all calls.
So, yes, the people who are responsible for evolving language know well that it is an anti-intuitive behavior, and it is a trap for anyone who does not study the language in depth - even if one has a lot of practice in other languages - but the option was in the past for not creating an exception in these cases - and today even if you thought differently, it is not possible to change because of the compatibility break. The best business is to understand this feature and use it to your advantage. (And if an IDE did not alert to the use of a list or dictionary as the default argument, it was right to open a bug against the IDE)
The behavior of a = a + b
and a += b
The behavior of +=
is given by the method __iadd__
if it exists in the left object class. If there is no - the __add__
is called (or __radd__
on the right object) - and the result is identical to the use of x = x + y
.
By convention also, the __iadd__
when it exists will modify the own object (self) - and the __add__
will create another instance.
So typically the implementation will be something like:
class F:
def __init__(self, valor):
self.valor = valor
def __add__(self, other):
return type(self)(valor=self.valor + other.valor)
def __iadd__(self, other):
self.valor += other.valor
return self
In the case of lists, and other mutable objects, that’s exactly what happens. So lista1 += lista2
will modify the list 1 internally, now
lista1 = lista1 + lista2
will create a new list that is the concatenation of lists list1 + Lista2 , and saves the result in the name lista1
, over-writing the previous reference.
If you have any reference to list1, before the line lista1 = lista1 + lista2
, that reference nay will see changes, and will continue pointing to the original "list1".
Understanding your problem based on these two things:
It’s simple: the line
self.listaFs[0].caixa= self.listaFs[0].caixa + ['ok']
creates a NEW list that will be a.caixa
-and then the objects b
and c
will still share the same list- but a.caixa
is being an independent list.
While the line:
self.listaFs[0].caixa+= ['ok']
changes the same instance of the list, which is in the a.caixa
-and then, how it remains shared in the instances b
and c
, you see this modification looking through those instances.
https://stackoverflow.com/a/823878/4802649
– Phiter
If one of the answers solved your problem, you can choose the one that solved it best (only one of them) and accept it, see here how and why to do it. It is not mandatory, but it is a good practice of the site, to indicate to future visitors that it solved the problem.
– hkotsubo