In the code I instantiate two different objects of the same class, how is it possible that object1
alters object2
's attributes? How can I keep different "self.mutable" variables? Where's my mistake? :-)
thanks
class Class:
mutable = {}
immutable = 0
def change(self):
self.immutable = 1
self.mutable["key"] = "value"
def observe(self):
print(self.immutable, self.mutable)
object1, object2 = Class(), Class()
object1.change()
object2.observe()
# output is: 0 {'key': 'value'}
You have defined mutable
and immutable
on the class level,
therefore both will be shared across all instances of Class
. The answers in the linked question explain in detail how to avoid the sharing behavior you are observing, so I will just explain what goes on with your code.
In principle, this sharing is unrelated to the attributes being mutable or immutable, but there are some nuances in your code that can make it confusing.
In the case of mutable
, the observed behavior is pretty easy to explain.
First of all, the dict mutable
is always the same object in memory:
>>> o1, o2 = Class(), Class()
>>> o1.mutable is o2.mutable is Class.mutable
True
when you mutate mutable
in any way, this change will be seen everywhere a reference to that dict is held.
>>> Class.mutable
{}
>>> o2.mutable[1] = 2
>>> o1.change()
>>> Class.mutable
{1: 2, 'key': 'value'}
So far all of this is expected. The tricky part with immutable
is that you don't mutate Class.immutable
in change, you assign the attribute immutable
to the instance (self
) change
is being called on!
Before calling change, immutable
only exists on the class level and is accessed through the class when looked up on the instance o1
or o2
. (Note how the instance dicts of o1
and o2
are empty.)
>>> o1, o2 = Class(), Class()
>>> o1.immutable, o2.immutable, Class.immutable
(0, 0, 0)
>>> o1.__dict__, o2.__dict__, 'immutable' in Class.__dict__
({}, {}, True)
When calling change
on o2
, you only set the attribute immutable = 1
on the instance o2
!
>>> o2.change()
>>> o1.immutable, o2.immutable, Class.immutable
(0, 1, 0)
>>> o1.__dict__, o2.__dict__, 'immutable' in Class.__dict__
({}, {'immutable': 1}, True)
>>> o1.immutable is Class.immutable
True
>>> o2.immutable is Class.immutable
False
It's important to understand that mutable and immutable objects set at the class level are shared in exactly the same way. The only difference is that mutable objects have no methods on them that change them. But if you had done self.mutable = {'key': 'value'}
in change
and then called change
on a specific instance, the mutable
attribute defined on the instance would take precedence over the attribute defined at the class level when looking it up on the instance via the dot-notation.