2

I am new to python.

Why am I not getting a new object when I call tempMyObject = myObject()?

class myObject(object):
  x = []

def getMyObject():
  tempMyObject = myObject()
  print "debug: %s"%str(tempMyObject.x)
  tempMyObject.x.append("a")
  return tempMyObject
#run
a = getMyObject()
b = getMyObject()

My debug prints out:

debug: []
debug: ["a"]

I don't understand why both of these debug arrays are not null, can someone please enlighten me?

EDIT: I found the mistake i put in python code on my post. I am using the .append("a") in my function

Quinma
  • 1,436
  • 2
  • 17
  • 39
  • 4
    you need a `def __init__(self)` inside your class – inspectorG4dget Jul 11 '13 at 20:14
  • 1
    Are you sure? I am no able to reproduce the same output. – Ashwini Chaudhary Jul 11 '13 at 20:14
  • Yes i am using python 2.6 – Quinma Jul 11 '13 at 20:17
  • @Quinma python version has nothing to do with your output, see : http://ideone.com/vSla8w – Ashwini Chaudhary Jul 11 '13 at 20:18
  • This question is just the class attribute version of the mutable default argument, which is in fact the [topmost question](http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument) in the [Frequent python questions](http://stackoverflow.com/questions/tagged/python?sort=frequent) list you can find under the Python tag. – Lennart Regebro Jul 11 '13 at 20:19
  • 4
    @LennartRegebro What? No. –  Jul 11 '13 at 20:19
  • 1
    NO, you are right, this isn't a mutable class attribute after all. Or rather, I think it is, but the example code above is not. The example code above does not give the output the OP claims. – Lennart Regebro Jul 11 '13 at 20:26
  • 1
    @LennartRegebro It does now, give it a try. I made a mistake when trasferring the code to Stack Overflow, sorry everybody – Quinma Jul 11 '13 at 20:28
  • 1
    @Quinma: Right, as I thought! You are using a mutable class attribute. This is the typical and most common newbie error, and pretty much everyone does it. It's based on the assumption that the object, in this case an empty list, is created when it is *used*, ie, in this case when you initialize the class. In fact it is created when *defined*. So each instance of myObject will share the exact same list. – Lennart Regebro Jul 11 '13 at 20:30

2 Answers2

6

You have created x as a class variable rather than an instance variable. To associate the variable with a particular instance of a class, do something like this:

class myObject(object):
    def __init__(self): # The "constructor"
        self.x = [] # Assign x to this particular instance of myObject

>>> debug: []
>>> debug: []

For a little better explanation of what's going on, have a look at this little mockup that demonstrates the same thing, a little more explicitly (if also more verbosely).

class A(object):
    class_var = [] # make a list attached to the A *class*
    def __init__(self):
        self.instance_var = [] # make a list attached to any *instance* of A

print 'class var:', A.class_var # prints []
# print 'instance var:', A.instance_var # This would raise an AttributeError!

print

a = A() # Make an instance of the A class
print 'class var:', a.class_var # prints []
print 'instance var:', a.instance_var # prints []

print

# Now let's modify both variables
a.class_var.append(1)
a.instance_var.append(1)
print 'appended 1 to each list'
print 'class var:', a.class_var # prints [1]
print 'instance var:', a.instance_var # prints [1]

print

# So far so good. Let's make a new object...
b = A()
print 'made new object'
print 'class var:', b.class_var # prints [1], because this is the list bound to the class itself
print 'instance var:', b.instance_var # prints [], because this is the new list bound to the new object, b

print

b.class_var.append(1)
b.instance_var.append(1)
print 'class var:', b.class_var # prints [1, 1]
print 'instance var:', b.instance_var # prints [1]
Henry Keiter
  • 16,863
  • 7
  • 51
  • 80
  • +1, yes the constructor in python is that `__init__` function; it looked a little funny to me at first as well. – BlackVegetable Jul 11 '13 at 20:16
  • 2
    @BlackVegetable technically, it's the initialiser (as the object is already constructed), and `__new__` is the constructor, but yeah... – Jon Clements Jul 11 '13 at 20:16
  • 1
    Ah, that is a good point. I've never directly used the `__new__` magic. To someone coming from, say, Java, `__init__` sure looks like a constructor though. – BlackVegetable Jul 11 '13 at 20:17
  • @JonClements Indeed, my intention in writing "constructor" was just to make it a little more intuitive for someone coming from a non-Python background. – Henry Keiter Jul 11 '13 at 20:18
  • @JonClements `__init__` does exactly what other languages' *constructors* do. A constructor isn't the function that creates an object, it's the one which initializes the fresh object. –  Jul 11 '13 at 20:19
  • 1
    `x` is indeed a class variable, but OP is overriding that class variable `tempMyObject.x = ["a"]`, so his code should work fine. OP posted a wrong code. – Ashwini Chaudhary Jul 11 '13 at 20:24
  • 1
    @AshwiniChaudhary Looks like he just edited it to make the problem reproducible-- `append` instead of reassignment (which was what I thought he was doing anyway, whoops) – Henry Keiter Jul 11 '13 at 20:27
  • @HenryKeiter Thank you for the explanation, and sorry for the wrong code. I had to dumb down my actual code into that and missed or rather overlooked the .append vs direct assignment thinking it was unimportant at the time. – Quinma Jul 11 '13 at 20:58
1

There a few bits missing in your code, like the class initialiser first and foremost. The correct code is as follows:

class myObject(object):
    def __init__(self):
         self.x=[] #Set x as an attribute of this object.

def getMyObject():
  tempMyObject = myObject()
  print "debug: %s"%str(tempMyObject.x) #Just after object initialisation this is an     empty list.
  tempMyObject.x = ["a"]
  print "debug2: %s"%str(tempMyObject.x) #Now we set a value to it.
  return tempMyObject
#run
a = getMyObject()
b = getMyObject()

Now the debug will first print out an empty list and then, once it was set, "a". Hope this helps. I recommend looking at basic python classes tutorial.

Aleksander Lidtke
  • 2,876
  • 4
  • 29
  • 41