Python Class Attribute Inconsistency
Solution 1:
I will extend your example a bit
class Bag:
items = []
items1 = []
val = 100
def add(self, x):
self.items.append(x)
self.val += 1self.items1 += [x]
b1 = Bag()
print(Bag.__dict__)
#op-1>>> 'items': [], 'items1': [], 'val': 100,
print(b1.__dict__)
#op-2>>> {}
b1.add(111)
print(Bag.__dict__)
#op-3>>> {'items': [111], 'items1': [111], 'val': 100}
print(b1.__dict__)
#op-4>>>{'items1': [111], 'val': 101}
To go step-by-step:
self.items.append(x)
:First, python tries to find if we have a
items
in theobject (self.__dict__)
, if not then it tries to finditems
from the class scope and appends it. Nothing is returned as part of this expression.self.__dict__
is untouched after this expression.self.val += 1
This is augmented assignment for int. So
__iadd__
will be called, if this is not implemented 's__add__
will be called which will always return a new int. The old int is not changed in-place because it is immutable. To elaborateself.val = self.val + 1
The first time
self.val
on therhs
refers to the class attribute (since b1.dict does not have it) and it creates a new int which is now stored in the object's__dict__
(because of lhs).. The second timeself.val
in therhs
refers to the val inself.__dict__
Instead if you would have doneBag.val += 1
, then it will always manipulate the class variable (like your second example)self.items1 += [x]
So this is also augmented addition of the list.__iadd__
. self.items1
is changed in-place for mutable sequences and the reference to the same list is also returned as part of this expression. So, after this statement, you should see that self.__dict__
will contain items1
but with same contents as Bag.__dict__['items1']
.
Your second example is altogether different:
cls.cl_roll += 1
this statement always manipulates the class variable.
Solution 2:
The list items
is one shared object among all the instances of your class. You modify it with self.items.append(x)
but you don't ever create another list. So every reference to .items
is working on the shared object Bag.items
However, when you do
b1.val += 1
This is like writing
b1.val = b1.val + 1
And because b1
does not yet have an individual value for val
, the effect you get is:
b1.val = Bag.val + 1
You are assigning to b1.val
a new value that is different from Bag.val
.
So your instances have a shared items
, but have individual val
, because you actually assign to b1.val
etc.
Post a Comment for "Python Class Attribute Inconsistency"