0

I create several instances of my class in a loop and expect those to be independent. But to my confusion, when I create a new instance with the same name, it keeps properties of the instance created before.

So I have something like:

class myClass(object):
    def __init__(self, i1 = None, i2 = 'X', p1 = [], p2 = []):
        self.i1, self.i2 = i1,i2
        self.property1 = p1
        self.property2 = p2

    def doStuff(self):        
        self.property1.append(self.i1)
        self.property2.append(self.i2)
        print self.property1
        print self.property2

class mySubClass(myClass):
    def __init__(self, i1 = None, i2 = 'Z'):
        myClass.__init__(self, i1, i2)



inputTuples = (('A', 'B'), ('D', 'E'))

for x,y in inputTuples:
    o=mySubClass(x)
    pprint(vars(o))
    o.doStuff()
    print(id(o))


{'i1': 'A', 'i2': 'Z', 'property1': [], 'property2': []}
['A']
['Z']
37087832
{'i1': 'D', 'i2': 'Z', 'property1': ['A'], 'property2': ['Z']}
['A', 'D']
['Z', 'Z']
37088392

So for the 1st time it loops, pprint shows o.property1 =[] For the second time, it shows o.property1 is a list of whatever got appended to o in the first run of the loop.

My understanding was that when I call o=myClass(), a new instance of that class would be created and the old one will be deleted (effectively overwrtitten)

Could anyone explain to me how python works here and how I could make it work the way I want?

If I change the class to

class myClass(object):
    def __init__(self, i1 = None, i2 = 'X':
        self.i1, self.i2 = i1,i2
        self.property1 = []
        self.property2 = []

it works fine

{'i1': 'A', 'i2': 'Z', 'property1': [], 'property2': []}
['A']
['Z']
37087832
{'i1': 'D', 'i2': 'Z', 'property1': [], 'property2': []}
['D']
['Z']
37088392

I dont understand the fundamental difference here. Also, how can I keep the possibility of having p1 and p2 as input variables and still ahve the desired behaviour?

chrise
  • 4,039
  • 3
  • 39
  • 74
  • 7
    This code isn't actually runnable, and it's hard to understand what your actual code does. Please try to construct a [SSCCE](http://sscce.org) that demonstrates the question. – abarnert Jul 03 '13 at 19:41
  • 4
    I'm guessing that while the code you're writing doesn't reflect this, you are actually using class variables (not the `self.property1 = []` that you're showing here). Those are indeed shared between class instances. But you need to make an actually reproducible example of your problem for us to have any idea what it is – David Robinson Jul 03 '13 at 19:42
  • Each time you instantiate a class (`myClass()`) it creates a new object, so it won't "overwrite" any other instances of that class. – a-b-r-o-w-n Jul 03 '13 at 19:44
  • 1
    Another possibility is that you've used a default parameter like: `def __init__(self, i1 = [])` and are not aware of the odd behavior of default parameters that are modifiable objects like lists and dictionaries. We can't tell because the posted code is not the real code, since it's not runnable. – torek Jul 03 '13 at 19:47
  • edited with executable code – chrise Jul 04 '13 at 08:59
  • found the answer here. thanks for the hint torek http://stackoverflow.com/questions/8145971/odd-behaviour-of-pythons-class – chrise Jul 04 '13 at 09:16

1 Answers1

3

I've modified your code to be actually runnable, and to show the identity of the o object each time through the loop. It would be better to strip out all the clearly extraneous stuff, but maybe this will way be easier for you to understand.

from pprint import pprint

def f(x, y):
    return x+y

class myClass(object):
    def __init__(self, i1,i2,i3):
        self.i1, self.i2, self.i3 = i1,i2,i3
        self.property1 =[]

    def doStuff(self):
        someValue = f(self.i1,self.i2)
        self.property1.append(someValue)

inputTuples = ((1, 2, 3), (4, 5, 6))

for x,y,z in inputTuples:
    o=myClass(i1=x,i2=y,i3=z)
    pprint(vars(o))
    o.doStuff()
    print(id(o))

When you run this, you will see output something like this:

{'i1': 1, 'i2': 2, 'i3': 3, 'property1': []}
4302258000
{'i1': 4, 'i2': 5, 'i3': 6, 'property1': []}
4302258064

In other words, each successive o instance has different properties, and is also a different object. Python really is creating a new o every time through the loop.

It may or may not destroy the old instance immediately,* but you don't care about that; it will destroy it "eventually" and do a good enough job of that, so you can just forget about it.


* With this particular code, CPython will destroy the old instance immediately; PyPy, Jython, and IronPython will usually destroy it either on the next collector pass, but some of them may just move or mark it and destroy it on the following pass.

abarnert
  • 354,177
  • 51
  • 601
  • 671