1

I've got a project where there is a list that contains a large number of user-defined objects. Each object itself has a variable that contains a list of its own. Why is it that when I append something to the list inside of each object, it gets applied to every object in the master list?

Take the following code for example:

class Example:
    inner_arr = []
    def __init__(self,name):
        self.name = name

class_list = []
for i in range(10):
    class_list.append(Example("Trial #:{i}".format(i=i)))

for i in range(len(class_list)):
    if i % 3 == 0:
        class_list[i].inner_arr.append("Divisible by 3")

for i in class_list:
    print(i.inner_arr)

In theory, the ".append('Divisible by 3')" should only be applied to the 1st, 4th, 7th, and 9th objects in the class_list, so the expected result should look like this:

['Divisible by 3']
[]
[]
['Divisible by 3']
[]
[]
['Divisible by 3']
[]
[]
['Divisible by 3']

But instead we get this mess:

['Divisible by 3', 'Divisible by 3', 'Divisible by 3', 'Divisible by 3']
['Divisible by 3', 'Divisible by 3', 'Divisible by 3', 'Divisible by 3']
['Divisible by 3', 'Divisible by 3', 'Divisible by 3', 'Divisible by 3']
['Divisible by 3', 'Divisible by 3', 'Divisible by 3', 'Divisible by 3']
['Divisible by 3', 'Divisible by 3', 'Divisible by 3', 'Divisible by 3']
['Divisible by 3', 'Divisible by 3', 'Divisible by 3', 'Divisible by 3']
['Divisible by 3', 'Divisible by 3', 'Divisible by 3', 'Divisible by 3']
['Divisible by 3', 'Divisible by 3', 'Divisible by 3', 'Divisible by 3']
['Divisible by 3', 'Divisible by 3', 'Divisible by 3', 'Divisible by 3']
['Divisible by 3', 'Divisible by 3', 'Divisible by 3', 'Divisible by 3']

I've tried rewriting this using dictionaries, using every possible method for updating lists. Strangely enough this behavior only occurs when the object's variable is a list. If the object's variable is a string, it works exactly as expected. I'm sure this is user error, but I cannot figure out what I am missing in all of this. Any help or advice is appreciated. Thanks in advance.

Pat K.
  • 11
  • 1
  • 1
    Does this answer your question? [How to avoid having class data shared among instances?](https://stackoverflow.com/questions/1680528/how-to-avoid-having-class-data-shared-among-instances) – MisterMiyagi May 24 '20 at 08:08
  • You may now think about [accepting an answer](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) or comment one to get details ;) to reward those who spent time for you ;) – azro May 31 '20 at 12:22

3 Answers3

2

When you declare an attribut directly in the class scope, not to self inside a method, this becomes a class variable, all instances will share it, you need to instanciate in the constructor and assign it to self to get an instance variable :

class Example:
    def __init__(self,name):
        self.name = name
        self.inner_arr = []

You can read more at Class&Instance Variable, that contains the exact example of your problem

azro
  • 53,056
  • 7
  • 34
  • 70
1

Wonderful you discovered the difference between visibility for variables in classes!

class A:
    a = [] # this is variable common to the class

# each instance of A will share the same list!

class B:
    def __init__(self, b):
        self.b = b # see how we use self, these is bounded to the object!

# each instance of B instead will have its private instance of the list
# available as the attribute b
edoput
  • 1,212
  • 9
  • 17
0

try this. If you declare variable inside class and it doesn't start with "self." then the varible has same value for every instance and if you change it in one instance, it changes in every.

class Example:
    def __init__(self,name):
        self.name = name
        self.inner_arr = []

class_list = []
for i in range(10):
    class_list.append(Example("Trial #:{i}".format(i=i)))

for i in range(len(class_list)):
    if i % 3 == 0:
        class_list[i].inner_arr.append("Divisible by 3")

for i in class_list:
    print(i.inner_arr)

  • Please always also write down an explanation why the OP's code doesn't work, and this does. – Tomalak May 24 '20 at 08:01
  • Wonderful! Thank you! Is there a particular reason why this happens though? Just for my own future reference. – Pat K. May 24 '20 at 08:02
  • In your method, inner_arr belongs to the class, while here inner_arr belongs to the instance of the class. – Ahmet May 24 '20 at 08:07
  • `the variable has same value` no, this is just the same variable that's it – azro May 24 '20 at 08:08