I have just recently battled a bug in Python. It was one of those silly newbie bugs, but it got me thinking about the mechanisms of Python (I\'m a long time C++ programmer,
What you keep referring to as a bug is the documented, standard behavior of Python classes.
Declaring a dict outside of __init__
as you initially did is declaring a class-level variable. It is only created once at first, whenever you create new objects it will reuse this same dict. To create instance variables, you declare them with self
in __init__
; its as simple as that.
When you access attribute of instance, say, self.foo, python will first find 'foo' in self.__dict__
. If not found, python will find 'foo' in TheClass.__dict__
In your case, dict1
is of class A, not instance.
@Matthew : Please review the difference between a class member and an object member in Object Oriented Programming. This problem happens because of the declaration of the original dict makes it a class member, and not an object member (as was the original poster's intent.) Consequently, it exists once for (is shared accross) all instances of the class (ie once for the class itself, as a member of the class object itself) so the behaviour is perfectly correct.
Pythons class declarations are executed as a code block and any local variable definitions (of which function definitions are a special kind of) are stored in the constructed class instance. Due to the way attribute look up works in Python, if an attribute is not found on the instance the value on the class is used.
The is an interesting article about the class syntax on the history of Python blog.
If this is your code:
class ClassA:
dict1 = {}
a = ClassA()
Then you probably expected this to happen inside Python:
class ClassA:
__defaults__['dict1'] = {}
a = instance(ClassA)
# a bit of pseudo-code here:
for name, value in ClassA.__defaults__:
a.<name> = value
As far as I can tell, that is what happens, except that a dict
has its pointer copied, instead of the value, which is the default behaviour everywhere in Python. Look at this code:
a = {}
b = a
a['foo'] = 'bar'
print b