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
itemsin theobject (self.__dict__), if not then it tries to finditemsfrom the class scope and appends it. Nothing is returned as part of this expression.self.__dict__is untouched after this expression.self.val += 1This 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.valon therhsrefers 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.valin therhsrefers 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.items1is 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 += 1This is like writing
b1.val = b1.val + 1And because b1 does not yet have an individual value for val, the effect you get is:
b1.val = Bag.val + 1You 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"