I got a strange behavior with python class, that doesn't seem normal to me, could you take time to help me on that ?
The code has been executed under python 3.9 and 3.6.
I got multiple instances from the same class:
class Obj:
txt_list = []
txt_dictionnary = {}
txt_var = ""
def __init__(self, txt):
self.txt_list.append(txt)
self.txt_dictionnary["hello"] = txt
self.txt_var = txt
Main code :
if __name__ == '__main__':
Obj1 = Obj("1")
print(f"txt_list1 = {Obj1.txt_list} - txt_dictionnary1 = {Obj1.txt_dictionnary} - txt_var1 = {Obj1.txt_var}")
Obj2 = Obj("2")
print(f"txt_list1 = {Obj1.txt_list} - txt_dictionnary1 = {Obj1.txt_dictionnary} - txt_var1 = {Obj1.txt_var}")
Obj2.txt_list.append("3")
print(f"txt_list1 = {Obj1.txt_list} - txt_dictionnary1 = {Obj1.txt_dictionnary} - txt_var1 = {Obj1.txt_var}")
Output :
txt_list1 = ['1'] - txt_dictionnary1 = {'hello': '1'} - txt_var1 = 1
txt_list1 = ['1', '2'] - txt_dictionnary1 = {'hello': '2'} - txt_var1 = 1
txt_list1 = ['1', '2', '3'] - txt_dictionnary1 = {'hello': '2'} - txt_var1 = 1
For me Obj1
shouldn't be changed when I instantiate and modify the Obj2
since Obj1
and Obj2
.
We also see, only the simple variable don't change on modification/instantiation.
Did I forget something ?
CodePudding user response:
txt_list
here is a class variable, which means it is shared between all instances of the class. If you mutate it(like with append
method), all the instances of the class will see the change.
In order to create a variable for each instance, you need to define an instance variable:
class Obj:
def __init__(self, txt):
self.txt_list = [txt]
self.txt_dictionnary = {'hello': txt}
self.txt_var = txt
now txt_list
is for individual instances, if you mutate it, no other instances will see the change.
I removed those lines from the class body, but I should mention that as long as you have those instance variables, you get the instance variables first. Even if they are defined as class variables as well.
class Obj:
txt_list = []
txt_dictionnary = {}
txt_var = ""
def __init__(self, txt):
self.txt_list = [txt]
self.txt_dictionnary = {'hello': txt}
self.txt_var = txt
This is how attribute lookup works in Python.(There are other cases where descriptors come into play but that's not our concern at the moment. Just be aware that them)
You mention that:
only the simple variable don't change on modification/instantiation.
That is because strings are immutable. You can't mutate it. When you do assignment, it doesn't mutate the object. So basically you create txt_var
as instance variable.
CodePudding user response:
You're declaring txt_list
, txt_dictionnary
, and txt_var
as class attributes.
As a result, all instances of your class share the same list and dictionary object, rather than have their own unique object.
Declare your attributes inside __init__()
instead:
def __init__(self, txt):
self.txt_list = [txt]
self.txt_dictionnary = { "hello": txt }
self.txt_var = txt