Home > Net >  Python - Class list and dictionnary linked between instance
Python - Class list and dictionnary linked between instance

Time:06-12

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
  • Related