class variable won't icrement!
Eric Brunel
eric.brunel at pragmadev.com
Thu Sep 12 05:48:33 EDT 2002
Gumuz wrote:
> Hello everyone,
>
> I have something very strange and i can not understand it. probably, it's
> not _that_ strange : )
>
> I have this simple class which registers itself on a class variable in the
> following code:
>
>
----------------------------------------------------------------------------
> ------
> class test:
> dict = {}
> id = 1
> def __init__(self, name):
> self.dict[name] = self
> self.id = self.id + 1
>
> def show(self):
> print "class variable dict element count: ", str(len(self.dict))
> print "class variable id: ", self.id
>
----------------------------------------------------------------------------
> --------
>
> now, look at the following:
>
>>>> john = test("john")
>>>> frank = test("frank")
>>>> bill = test("bill")
>>>> bill.show()
> class variable dict element count: 3
> class variable id: 2
>>>> frank.show()
> class variable dict element count: 3
> class variable id: 2
>
> The dict variable acts fine, maintaining it's content throughout every
> instance of the class.
> The id variable however, seems to be only incremented within the instance.
> In the end this variable should've been 4.
>
> Could someone explain this to me? Is there something about class variables
> whta i should know?
Yep: to access them, you'd better always use the syntax <class
name>.<attribute name>. Instances do in fact "inherit" the attributes of
their class, but it leads to misunderstandings just as yours. In your
example, here is what happens:
> class test:
> dict = {}
Here, you create an attribute dict for class test. The value for this
attribute is an *object*, which is *mutable*, that happens to be an empty
dictionary.
> id = 1
Here, you create an attribute id for class test. The value for this
attribute is an *integer*, which is *not* an object, and is *immutable*.
> def __init__(self, name):
> self.dict[name] = self
Here, you use the attribute dict, inherited from the class, and you modify
it. These modifications happens *in place*, which means that the pointed
dictionary is actully modified. Since both test.dict and self.dict point to
the same object, they'll both see the modification. This is exactly the
same if you do:
a = {}
b = a
b['foo'] = 'bar'
print a
You'll see that a has been modified. In your example, here is roughly what
happens:
test.dict = {}
self.dict = test.dict # Implicit inheritance from class to instance
self.dict[name] = self
> self.id = self.id + 1
This is a completely different story: here, you *recreate* an instance
attribute named id, based on the id attribute inherited from the class. So,
in fact, you're doing:
test.id = 1
self.id = test.id # Again, implicit inheritance from class to instance
self.id = self.id + 1
just as in:
a = 1
b = a
b = b + 1
print a
Of course, a is not modified here...
I always found that inheritance of class attributes to instance attributes
was really misleading, and I even think it would be better if it were
simply removed from Python. IMHO, it would far more conform to the
"explicit is better than implicit" rule that is one of the basis of Python.
To avoid its drawbacks:
- never declare as a class attribute something that's actually an instance
attribute
- always use <class name>.<attribute name> to access class attributes,
especially when you modify them
HTH
--
- Eric Brunel <eric.brunel at pragmadev.com> -
PragmaDev : Real Time Software Development Tools - http://www.pragmadev.com
More information about the Python-list
mailing list