Reputation: 836
The common example when talking about class attributes in python, is the following:
Python 2.7.6 (default, Sep 9 2014, 15:04:36)
>>> class B(object):
... cv = []
...
>>> b1 = B()
>>> b2 = B()
>>> b1.cv, b2.cv, B.cv
([], [], [])
>>> b1.cv.append(1)
>>> b1.cv, b2.cv, B.cv
([1], [1], [1])
>>> b2.cv.append(2)
>>> b1.cv, b2.cv, B.cv
([1, 2], [1, 2], [1, 2])
>>> B.cv.append(3)
>>> b1.cv, b2.cv, B.cv
([1, 2, 3], [1, 2, 3], [1, 2, 3])
It shows that class attribute is shared between class and all its instances.
But here is what happens when we reassign the value of class attribute, i.e. without the mutation of initial object bounded to a class attribute:
>>> class A(object):
... cv = 0
...
>>> a1 = A()
>>> a2 = A()
>>> a1.cv, a2.cv, A.cv
(0, 0, 0)
>>> a1.cv = 1
>>> a1.cv, a2.cv, A.cv
(1, 0, 0)
>>> a2.cv = 2
>>> a1.cv, a2.cv, A.cv
(1, 2, 0)
>>> A.cv = 3
>>> a1.cv, a2.cv, A.cv
(1, 2, 3)
Here we can see that each time this class attribute stores its unique value, and it will not be overridden in next assignments applied at both instance and class namespaces.
Why is this behavior like this?
I can't understand what kind of this logic may be that it leads to so 'not relevant' behaviors for "immutable" (A) and "mutable" (B) cases.. This makes me think of "no any sense of using class variables" as they may be prone to mistakes...
I hope that's me who does not see the light in this tunnel...
Upvotes: 1
Views: 155
Reputation: 16711
You can use class attributes effectively if you don't intend to use them through instances. For example, I like to manage a group of objects of the same class in the class attributes. If you've ever heard of Pygame, that's where I tend to use this technique most often.
class Alien:
sprites = []
def __init__(self, x, y):
self.surf = pygame.image.load('Alien.png')
self.rect = self.surf.get_rect()
self.rect.topleft = (x, y)
Alien.sprites.append(self)
@staticmethod
def draw_sprites(screen):
for sprite in Alien.sprites:
screen.blit(sprite.surf, sprite.rect)
Do you see how object management can be this easy with class methods and attributes?
Upvotes: 0
Reputation: 836
Just one more final example explaining the answer by Chris Warrick
>>> A.cv = 0
>>> a1, a2 = A(), A()
>>> A.cv, a1.cv, a2.cv
(0, 0, 0)
>>> A.cv = 1
>>> A.cv, a1.cv, a2.cv
(1, 1, 1)
>>> a1.cv = 2 # Here the new instance attribute is created for a1,
# and so it will hide the class attribute with the same name,
# once getting the value from instance namespace
>>> A.cv, a1.cv, a2.cv
(1, 2, 1)
>>> A.cv = 3
>>> A.cv, a1.cv, a2.cv
(3, 2, 3)
Upvotes: 1
Reputation: 1629
In the first example, you mutate the list. There is only one instance of the list in the universe, B.__dict__['cv']
. In the second example, you assign values. When you do this, they assignments are made in each specific instance a(1|2|3)
, because that’s how attribute setting works in Python (it saves to the __dict__
of whatever you are trying to change an attribute of). You would have to modify A.cv
to modify everything, and any changes made in a(1|2|3)
would override the changes made.
(Python tries to use a(1|2|3).__dict__
and then falls back to A.__dict__
.)
Upvotes: 2