Skip to content Skip to sidebar Skip to footer

Python Class Attribute Inconsistency

I am trying to understand how class attributes work in Python. I have confusion based on following example. #!/usr/bin/python3 class Bag: val = 100 items = [] def add

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:

  1. self.items.append(x):

    First, python tries to find if we have a items in the object (self.__dict__), if not then it tries to find items from the class scope and appends it. Nothing is returned as part of this expression. self.__dict__ is untouched after this expression.

  2. 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 elaborate

    self.val = self.val + 1

    The first time self.val on the rhs 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 time self.val in the rhs refers to the val in self.__dict__ Instead if you would have done Bag.val += 1, then it will always manipulate the class variable (like your second example)

  3. 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 += 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"