1

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

4
  • 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. Commented Mar 7, 2015 at 19:27
  • Aye when I see this i thought, 'a1.cv!? a2.cv!? those are static class variables!' and I find it quite disconcerting that Python lets you mix-and-match how it is used. I would refrain from ever accessing a class static through instance members and never know there was an issue. As to why Python lets you do the above code - I guess that's explained in the below answer but it seems like a good way to get into trouble ;p Commented Mar 7, 2015 at 19:38
  • @MalikBrahimi, it would be great if you provide some tiny example of such technique, just to understand the real case where this can be used... And put some link to gist or pastebin, or whatever... Thank you! Commented Mar 8, 2015 at 0:23
  • @yashaka Just give me a minute and I'll have a post. Commented Mar 8, 2015 at 0:26

3 Answers 3

2

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__.)

Sign up to request clarification or add additional context in comments.

Comments

1

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)

Comments

0

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?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.