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:
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".
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With