Lists are weird when they are instance members

P

python newbie

hey,
okay, I'm trying to figure out why my books: Quick Python, Python in a
Nutshell, Python Cookbook and Learning Python don't say anything about the
weird behavior of a list when you have one as an object instance member.

for instance (my first pun of 2004), if I have,

test.py
----------------

global_filegroup_array = [] # array of filegroup objects

class FileGroup:
a = 0
mylist = [] # here it is

def put_stuff_in_my_list(self, anyfile):
self.mylist.append( get just a single string from file) #
pls excuse the psuedo

def __init__(self):
put_stuff_in_my_list(anyfile)

def main(): # do ten times: instantiate the
above object, and add to the global array
for i in xrange(10):
filegroup = FileGroup()
global_filegroup_array.append(filegroup)


# print the list contents
print global_filegroup_array[0].mylist

------------ end of file

Output is: [u'.string1', u'.string2', u'.string3' ] # only
u'string1' should show up

No matter which index I use into the global array, I always get ALL of
the strings
showing up. I should only get u'string1' showing up, and u'string2'
if
I used "[1].mylist"


How I resolved it, is by slipping in

self.mylist = []

before

put_stuff_in_my_list(anyfile)

in __init__(self)

Why should I have to empty out the list when it's a member of a newly
instantiated object?

thanks

p.s. ( I'm actually not doing exactly the thing with the
files, but instead iterating through a xml file with dom,
debugging it showed the behavior )
 
M

Mathias Waack

python said:
test.py
----------------

global_filegroup_array = [] # array of filegroup objects

class FileGroup:
a = 0
mylist = [] # here it is

This is a class variable, not a member or instance variable. Make
sure you know the difference.
def put_stuff_in_my_list(self, anyfile):
self.mylist.append( get just a single string from
file)

This line creates a member variable "mylist" of the current instance
"self" of class "FileGroup" as a copy of the class variable
"FileGroup.mylist".

Just create your member variables in the c'tor function __init__.
This should solve all your problems (ok, at least this problem;)

And btw. Python in a nutshell (I haven't read the other books you've
mentioned) explains the differences between class and member
variables.

Mathias
 
R

Robin Becker

I think you're not grokking that using

class A:
mylist = []

makes mylist a class attribute ie all instances share the same version
of mylist. To get an instance version you need to assign self.mylist.
That would normally be done using an __init__method. so

class A:
def __init__(self):
self.mylist = []

then each instance sets up its own empty list at creation time.

Hope that helps.
 
T

Troels Therkelsen

hey,
okay, I'm trying to figure out why my books: Quick Python, Python in a
Nutshell, Python Cookbook and Learning Python don't say anything about the
weird behavior of a list when you have one as an object instance member.

for instance (my first pun of 2004), if I have,

test.py
----------------

global_filegroup_array = [] # array of filegroup objects

class FileGroup:
a = 0
mylist = [] # here it is

mylist in this case is a class variable; what this means is that it is shared
amongst all *instances* of the class. Only if an instance of the class rebinds
mylist is it local to the particular class instance doing this.
def put_stuff_in_my_list(self, anyfile):
self.mylist.append( get just a single string from file) #
pls excuse the psuedo

Because lists are mutable, when you use mylist.append(...) you don't rebind
mylist, but change its contents. Since mylist is a class variable, this
change is available to the class as well as all instances of the class.
def __init__(self):
put_stuff_in_my_list(anyfile)

def main(): # do ten times: instantiate the
above object, and add to the global array
for i in xrange(10):
filegroup = FileGroup()
global_filegroup_array.append(filegroup)


# print the list contents
print global_filegroup_array[0].mylist

------------ end of file

Output is: [u'.string1', u'.string2', u'.string3' ] # only
u'string1' should show up

No matter which index I use into the global array, I always get ALL of
the strings
showing up. I should only get u'string1' showing up, and u'string2'
if
I used "[1].mylist"


How I resolved it, is by slipping in

self.mylist = []

before

put_stuff_in_my_list(anyfile)

in __init__(self)

Why should I have to empty out the list when it's a member of a newly
instantiated object?

Because __init__() is called when a class is about to be instantiated. You are
masking the *class variable* mylist with a local *instance variable* of the
same name. The latter is not shared amongst all instances of the class, but
remains unique to the particular instance.

Hope this helps,

/Troels Therkelsen
 
P

python newbie

thanks for the helpful replies.
I guess I was just in confusion as to why I was able to leave alone the
string variables in class FileGroup, such
as sourceDir and destinDir, and nothing unpredictable happened with those,
but with the list variable, I had to treat differently.
But after I again read closely, Python In a Nutshell, I'm sure I will
understand.
 
P

python newbie

I didn't say that right. I meant to say that I now finally understood
what's going on now, with your replies, but I will take a slight break from
the app I'm writing, and do some ingesting of the core Python concepts.
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,012
Latest member
RoxanneDzm

Latest Threads

Top