Python Class Members Initialization
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, new to Python). I will lay out the buggy code and explain what I did to fix it, and then I have a couple of questions...
The scenario: I have a class called A, that has a dictionary data member, following is its code (this is simplification of course):
class A:
dict1={}
def add_stuff_to_1(self, k, v):
self.dict1[k]=v
def print_stuff(self):
print(self.dict1)
The class using this code is class B:
class B:
def do_something_with_a1(self):
a_instance = A()
a_instance.print_stuff()
a_instance.add_stuff_to_1('a', 1)
a_instance.add_stuff_to_1('b', 2)
a_instance.print_stuff()
def do_something_with_a2(self):
a_instance = A()
a_instance.print_stuff()
a_instance.add_stuff_to_1('c', 1)
a_instance.add_stuff_to_1('d', 2)
a_instance.print_stuff()
def do_something_with_a3(self):
a_instance = A()
a_instance.print_stuff()
a_instance.add_stuff_to_1('e', 1)
a_instance.add_stuff_to_1('f', 2)
a_instance.print_stuff()
def __init__(self):
self.do_something_with_a1()
print("---")
self.do_something_with_a2()
print("---")
self.do_something_with_a3()
Notice that every call to do_something_with_aX()
initializes a new "clean" instance of class A, and prints the dictionary before and after the addition.
The bug (in case you haven't figured it out yet):
>>> b_instance = B()
{}
{'a': 1, 'b': 2}
---
{'a': 1, 'b': 2}
{'a': 1, 'c': 1, 'b': 2, 'd': 2}
---
{'a': 1, 'c': 1, 'b': 2, 'd': 2}
{'a': 1, 'c': 1, 'b': 2, 'e': 1, 'd': 2, 'f': 2}
In the second initialization of class A, the dictionaries are not empty, but start with the contents of the last initialization, and so forth. I expected them to start "fresh".
What solves this "bug" is obviously adding:
self.dict1 = {}
In the __init__
constructor of class A. However, that made me wonder:
- What is the meaning of the "dict1 = {}" initialization at the point of dict1's declaration (first line in class A)? It is meaningless?
- What's the mechanism of instantiation that causes copying the reference from the last initialization?
- If I add "self.dict1 = {}" in the constructor (or any other data member), how does it not affect the dictionary member of previously initialized instances?
EDIT: Following the answers I now understand that by declaring a data member and not referring to it in the __init__
or somewhere else as self.dict1, I'm practically defining what's called in C++/Java a static data member. By calling it self.dict1 I'm making it "instance-bound".
Solution 1:
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.
Solution 2:
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.