1

I'm doing some practicing with OOP in python and I've run into an issue that my non-computer scientist mind cannot comprehend. I'm sure it's just due to my inexperience with OO but I can't seem to find an answer for it anywhere.

So I've got three classes. A class called tester, which should contain a unique object called group, which should contain a list of objects called atom. My issue is that whenever I create multiple groups they all seem to have the same list object. So whenever I append an atom to the list it gets appended to all the group's lists. My code is:

count = 0
testers = []

class atom:
    def __init__(self):
        pass

class group:
    myList = list()
    def __init__(self):
        pass

    def createAtom(self):
        self.myList.append(atom())


class tester:
    def __init__(self):
        self.myGroup = group()

for k in range(4):
    testers.append(tester())
    print testers[k].myGroup

for t in testers:
    t.myGroup.createAtom()
    print t.myGroup.myList

I would expect this to create a new list for each group and that this would add a single atom to each group. This instead creates an output as follows.

<__main__.group instance at 0x02C2E058>
<__main__.group instance at 0x02C2E0A8>
<__main__.group instance at 0x02C2E0F8>
<__main__.group instance at 0x02C2E148>
[<__main__.atom instance at 0x02C2E170>]
[<__main__.atom instance at 0x02C2E170>, <__main__.atom instance at 0x02C2E198>]
[<__main__.atom instance at 0x02C2E170>, <__main__.atom instance at 0x02C2E198>, <__main__.atom instance at 0x02C2E1C0>]
[<__main__.atom instance at 0x02C2E170>, <__main__.atom instance at 0x02C2E198>, <__main__.atom instance at 0x02C2E1C0>, <__main__.atom instance at 0x02C2E1E8>]

A single list gets all four atoms. I apologize for my likely poor code. If it's of any help, I'm using python portable 2.7.5.1. Any insight into this would be greatly appreciated.

Thanks

3 Answers3

3

Your list is a class attribute, shared amongst all instances:

class group:
    myList = [] # class attribute
    def __init__(self):
        pass

Instead, make it an instance attribute, separate for each instance of the class:

class group:
    def __init__(self):
        self.myList = [] # instance attribute

Note that I have replaced list() with [], per thefourtheye's comment. It is bad practice to shadow built-ins (e.g. having your own list or other object named list), but this avoids side effects if the rule gets broken.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • Recommend `[]`, `list` can be reassigned to something else. – thefourtheye Jan 23 '14 at 16:59
  • Ah. That worked if I made myList = list() into self.myList = list(). Am I correct in doing that? Also, what exactly makes something a class attribute vs. an instance attribute? Much appreciated! – user3228706 Jan 23 '14 at 17:01
  • @user3228706 class attributes are defined outside the instance methods (as you have done here) or using the class name (in this case, `group.myList`). Instance attributes are defined inside the instance methods, using (by convention) `self`, the specific class instance. – jonrsharpe Jan 23 '14 at 17:04
1

You've made group.myList a class attribute, shared by all instances.

class group:
    #myList = list()       # <--- this defines a 'class' attribute
                           #      which is shared by all instances of 'group'
    def __init__(self):
        self.myList = list()  # <--- do this instead to create an instance attribute

    def createAtom(self):
        self.myList.append(atom())
Community
  • 1
  • 1
Colin D Bennett
  • 11,294
  • 5
  • 49
  • 66
0

Move the mylist = list() in class group into the __init__ of class group.
Doing so would make group create a new list every time a new group instance is created. Otherwise, all you've done is create a class-level variable (not instance-level), which will be shared among all instances of the same class.

Think of class variables as sort of a "hive mind" (think of The Borg from Star Trek) structure for all instances of that class. Any changes made to a class variable will be visible to all objects of that type.

On the other hand, if you were to create an instance variable (a variable initialized in __init__), then each instance would have its own value for that variable. Thus any changes that one instance makes to its variable will be invisible to other instances of the same type

inspectorG4dget
  • 110,290
  • 27
  • 149
  • 241