instance puzzle

K

kaswoj

Hello, I have a question concerning python and object instances. In the
sample program below, several instances of the same class are made one after
the other. I would expect that the values of "num" and "list" are reset to
"0" and "[]" with each new instance created. But why the heck does this work
like expected for "num" but not for "list"?!
I'm really stuck and confused. Does anybody know what the problem is?
-- Dominik

class MyClass:
num = 0
list = []

def setVar(self, i):
if self.list == []: self.list.append(i)
if self.num == 0: self.num = i

for i in range(0, 4):
obj = MyClass()
obj.setVar(i)
print obj.list
print obj.num

Program output:
[0]
0
[0]
1
[0]
2
[0]
3

Program output I would expect:
[0]
0
[1]
1
[2]
2
[3]
3
 
M

Mark Day

class MyClass:
num = 0
list = []

def setVar(self, i):
if self.list == []: self.list.append(i)
if self.num == 0: self.num = i

for i in range(0, 4):
obj = MyClass()
obj.setVar(i)
print obj.list
print obj.num
[snip]

Program output I would expect:
[0]
0
[1]
1
[2]
2
[3]
3

Try removing the "if self.list == []: " from setVar, and you'll get
this output:

[0]
0
[0]
1
[0]
2
[0]
3
[0]
0
[0, 1]
1
[0, 1, 2]
2
[0, 1, 2, 3]
3

I think your confusion comes from the fact that num and list class
variables (is that the right term?), not instance variables. That is,
there is only one "num" or "list", shared by all instances of MyClass.
The first object gets created and appends 0 to the list. After that,
the list is not empty, so nothing else is appended (and the list
remains [0]).

To get the output you expected, change the class definition to:
class MyClass:
def __init__(self):
self.num = 0
self.list = []

def setVar(self, i):
self.list.append(i)
if self.num == 0: self.num = i

-Mark
 
A

Alexander Schmolck

kaswoj said:
Hello, I have a question concerning python and object instances. In the
sample program below, several instances of the same class are made one after
the other. I would expect that the values of "num" and "list" are reset to
"0" and "[]" with each new instance created. But why the heck does this work
like expected for "num" but not for "list"?!
I'm really stuck and confused. Does anybody know what the problem is?

Yep, I should think so; short explanation follows (It's late so clarity and
accuracy might suffer).


-- Dominik

class MyClass:

# these two are *class* variables shared between all instances of the class
num = 0
list = []

def setVar(self, i):
if self.list == []: self.list.append(i)

A) B)

This line looks up self.list twice (A) ,B) ). Since there is no instance
variable self.list, it resorts to the class variable MyClass.list. Then it
*mutates* it with append.
if self.num == 0: self.num = i

C) D)

This looks up self.num once and again resorts to the class variable ( C) ).
However assignment to self.XXX creates a new *binding* of a value to an
instance attribute name (even if there already is a class variable of the same
name). (Try adding the line ``print MyClass.num, self.num, MyClass.list,
self.list``)

I suspect what you want is:

class MyClass:
def __init__(self):
# run each time instance is created; viz. we create instance variables
self.num = 0
self.list = []


def setVar(self, i):
if self.list == []: self.list.append(i)



'as
 
T

Terry Reedy

kaswoj said:
Hello, I have a question concerning python and object instances. In the
sample program below, several instances of the same class are made one after
the other. I would expect that the values of "num" and "list" are reset to
"0" and "[]" with each new instance created.

As far as I can think, Python never automatically resets anything.
That includes both default parameter values and class attributes used
as default instance attributes.
But why the heck does this work like expected for "num" but not for
"list"?!

You shadow 'num' and mutate 'list' (which shadows builtin list())
class MyClass:
num = 0
list = []

def setVar(self, i):
if self.list == []: self.list.append(i)

This executes as "if MyClass.list == []: MyClass.list.append". On
the first call, [] is changed to [0] != [], so that is one and only
trigger and change.
if self.num == 0: self.num = i

This executes as "if MyClass.num == 0: instance.num=i". Since
MyClass.num remains the same, this always triggers.
for i in range(0, 4):
obj = MyClass()
obj.setVar(i)
print obj.list # == print MyClass.list == [0]
print obj.num

Program output:
[0]
0
[0]
1
[0]
2
[0]
3

Exactly as explained.

Terry J. Reedy
 
K

kaswoj

Thanks a lot you guys, i understand it now.
I think too much in java, so I always get into trouble trying to write
object oriented python programs :)
-- Dominik
 
P

PyUser

I think too much in java, so I always get into trouble trying to write
object oriented python programs :)

Just add a bit of self-ishness! Or how about 'this':

class MyClass:
def __init__(this, i):
this.num = 0
this.lst = []
-- Dominik
Sarat
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,166
Messages
2,570,907
Members
47,448
Latest member
DeanaQ4445

Latest Threads

Top