Help | Site Map
Connecting Tech Pros Worldwide
 
 
LinkBack Thread Tools
  #1  
Old December 28th, 2006, 05:25 PM
Ben
Guest
 
Posts: n/a
Default dictionary containing instances of classes behaving oddly

Hello...

I have a dictionary, where each value is a seperate instance of the
same class:

self.mop_list[record_number]=record(self.mops[:])

In my case I know that record_number takes the values 0,3,and 7 thanks
to a loop, giving me three instances of the record class instantiaterd
with some data I've pased in.

The record object contains a list, and each element of that list should
also contain an instance of a class should I append one to it:


self.mop_list[record_number].my_list.append(my_class(0,0,0,self.mop_list[record_no].mops,0))

So within each record class I have access to any number of my_class
instances, depending on how many times I have appended:

self.mop_list[record_number].my_list[index]


This seems to work without any errors. But bizzarely I find that
whatever my record number, the instance of "my_class" is appended to
every list. So in this case

self.mop_list[0].my_list.append(my_class(Some data for the
constructor))

I would expect to append an instance of my_class to
self.mop_list[0].my_list

But annoyingly

self.mop_list[0].my_list
self.mop_list[3].my_list
self.mop_list[7].my_list

all have an instance of my_class created and appended to them. This is
really confusing and quite annoying - I don't know whether anyone out
there can make head or tail of what I'm doing wrong?

Cheers,

Ben

  #2  
Old December 28th, 2006, 06:45 PM
Erik Johnson
Guest
 
Posts: n/a
Default Re: dictionary containing instances of classes behaving oddly


"Ben" <Benjamin.Barker@gmail.comwrote in message
news:1167326178.386764.300200@n51g2000cwc.googlegr oups.com...

<snip>
Quote:
This seems to work without any errors. But bizzarely I find that
whatever my record number, the instance of "my_class" is appended to
every list. So in this case
>
self.mop_list[0].my_list.append(my_class(Some data for the
constructor))
>
I would expect to append an instance of my_class to
self.mop_list[0].my_list
>
But annoyingly
>
self.mop_list[0].my_list
self.mop_list[3].my_list
self.mop_list[7].my_list
>
all have an instance of my_class created and appended to them. This is
really confusing and quite annoying - I don't know whether anyone out
there can make head or tail of what I'm doing wrong?
Well, it's a little bit difficult, but I think I actually know what's going
on. You probably need some code that looks something like this, to ensure
each object has it's own, independent list:

class record:
def __init__(self, init_list=None):
self.my_list = []
if init_list is not None:
self.my_list.extend(init_list)


Here's what I think you are doing, and below should make it clear why that
doesn't work:

class record:
def __init__(self, init_list=[]):

That list above, the default initializer is constructed just once (when the
def statement executes)!
Quote:
Quote:
Quote:
>>class record:
.... def __init__(self, init_list=[]):
.... self.my_list = init_list
....
Quote:
Quote:
Quote:
>>r1 = record()
>>r1.my_list
[]
Quote:
Quote:
Quote:
>>r2 = record()
>>r2.my_list
[]
Quote:
Quote:
Quote:
>>r2.my_list.append('boo!')
>>r1.my_list
['boo!']
Quote:
Quote:
Quote:
>>>
>>l1 = range(1, 4)
>>l1
[1, 2, 3]
Quote:
Quote:
Quote:
>>r1 = record(l1)
>>r2 = record(l1)
>>r1.my_list
[1, 2, 3]
Quote:
Quote:
Quote:
>>r2.my_list
[1, 2, 3]
Quote:
Quote:
Quote:
>>r1.my_list.append(42)
>>l1
[1, 2, 3, 42]
Quote:
Quote:
Quote:
>>r1.my_list
[1, 2, 3, 42]
Quote:
Quote:
Quote:
>>r2.my_list
[1, 2, 3, 42]
Quote:
Quote:
Quote:
>>>

  #3  
Old December 28th, 2006, 07:15 PM
Ben
Guest
 
Posts: n/a
Default Re: dictionary containing instances of classes behaving oddly

Ah - ok. In fact I simply had:

class record:
my_list =[]
mops=[]

def __init__(self,mops):
self.mops=mops

Where mops is something I pass in when i create the instance. I had
thought that then each time I created an instance of the record class
as an element of my dictionary:

self.mop_list[record_number]=record(self.mops[:])

I would create a brand new instance of the record class.It would have a
mops list initialized with mops (because the def__init__ constructor is
called when the class is instantiated), and an empty, individual list
my_list.

I could then access each individual list by doing:

self.mop_list[x].my_list[y]=something

But in fact the same my_list is being accessed for all values of x, so
a change to one list is in fact a change to them all. I think you might
be right, but can't quite work it out myself! I'll keep trying :-)

Thanks for your help,

Ben





Erik Johnson wrote:
Quote:
"Ben" <Benjamin.Barker@gmail.comwrote in message
news:1167326178.386764.300200@n51g2000cwc.googlegr oups.com...
>
<snip>
>
Quote:
This seems to work without any errors. But bizzarely I find that
whatever my record number, the instance of "my_class" is appended to
every list. So in this case

self.mop_list[0].my_list.append(my_class(Some data for the
constructor))

I would expect to append an instance of my_class to
self.mop_list[0].my_list

But annoyingly

self.mop_list[0].my_list
self.mop_list[3].my_list
self.mop_list[7].my_list

all have an instance of my_class created and appended to them. This is
really confusing and quite annoying - I don't know whether anyone out
there can make head or tail of what I'm doing wrong?
>
Well, it's a little bit difficult, but I think I actually know what's going
on. You probably need some code that looks something like this, to ensure
each object has it's own, independent list:
>
class record:
def __init__(self, init_list=None):
self.my_list = []
if init_list is not None:
self.my_list.extend(init_list)
>
>
Here's what I think you are doing, and below should make it clear why that
doesn't work:
>
class record:
def __init__(self, init_list=[]):
>
That list above, the default initializer is constructed just once (when the
def statement executes)!
>
Quote:
Quote:
>class record:
... def __init__(self, init_list=[]):
... self.my_list = init_list
...
Quote:
Quote:
>r1 = record()
>r1.my_list
[]
Quote:
Quote:
>r2 = record()
>r2.my_list
[]
Quote:
Quote:
>r2.my_list.append('boo!')
>r1.my_list
['boo!']
Quote:
Quote:
>>
>l1 = range(1, 4)
>l1
[1, 2, 3]
Quote:
Quote:
>r1 = record(l1)
>r2 = record(l1)
>r1.my_list
[1, 2, 3]
Quote:
Quote:
>r2.my_list
[1, 2, 3]
Quote:
Quote:
>r1.my_list.append(42)
>l1
[1, 2, 3, 42]
Quote:
Quote:
>r1.my_list
[1, 2, 3, 42]
Quote:
Quote:
>r2.my_list
[1, 2, 3, 42]
Quote:
Quote:
>>
  #4  
Old December 28th, 2006, 07:25 PM
Ben
Guest
 
Posts: n/a
Default Re: dictionary containing instances of classes behaving oddly

Ah - I have been very silly indeed!

I had not realised that by creating my lists outside of the
def__init___() constructor they would always be class rather than
instance variables, and so there was only one of them when I referred
to it. Thanks to Erik and Chris for your help!

Ben


Ben wrote:
Quote:
Ah - ok. In fact I simply had:
>
class record:
my_list =[]
mops=[]
>
def __init__(self,mops):
self.mops=mops
>
Where mops is something I pass in when i create the instance. I had
thought that then each time I created an instance of the record class
as an element of my dictionary:
>
self.mop_list[record_number]=record(self.mops[:])
>
I would create a brand new instance of the record class.It would have a
mops list initialized with mops (because the def__init__ constructor is
called when the class is instantiated), and an empty, individual list
my_list.
>
I could then access each individual list by doing:
>
self.mop_list[x].my_list[y]=something
>
But in fact the same my_list is being accessed for all values of x, so
a change to one list is in fact a change to them all. I think you might
be right, but can't quite work it out myself! I'll keep trying :-)
>
Thanks for your help,
>
Ben
>
>
>
>
>
Erik Johnson wrote:
>
Quote:
"Ben" <Benjamin.Barker@gmail.comwrote in message
news:1167326178.386764.300200@n51g2000cwc.googlegr oups.com...

<snip>
Quote:
This seems to work without any errors. But bizzarely I find that
whatever my record number, the instance of "my_class" is appended to
every list. So in this case
>
self.mop_list[0].my_list.append(my_class(Some data for the
constructor))
>
I would expect to append an instance of my_class to
self.mop_list[0].my_list
>
But annoyingly
>
self.mop_list[0].my_list
self.mop_list[3].my_list
self.mop_list[7].my_list
>
all have an instance of my_class created and appended to them. This is
really confusing and quite annoying - I don't know whether anyone out
there can make head or tail of what I'm doing wrong?
Well, it's a little bit difficult, but I think I actually know what's going
on. You probably need some code that looks something like this, to ensure
each object has it's own, independent list:

class record:
def __init__(self, init_list=None):
self.my_list = []
if init_list is not None:
self.my_list.extend(init_list)


Here's what I think you are doing, and below should make it clear why that
doesn't work:

class record:
def __init__(self, init_list=[]):

That list above, the default initializer is constructed just once (when the
def statement executes)!
Quote:
>>class record:
... def __init__(self, init_list=[]):
... self.my_list = init_list
...
Quote:
>>r1 = record()
>>r1.my_list
[]
Quote:
>>r2 = record()
>>r2.my_list
[]
Quote:
>>r2.my_list.append('boo!')
>>r1.my_list
['boo!']
Quote:
>>>
>>l1 = range(1, 4)
>>l1
[1, 2, 3]
Quote:
>>r1 = record(l1)
>>r2 = record(l1)
>>r1.my_list
[1, 2, 3]
Quote:
>>r2.my_list
[1, 2, 3]
Quote:
>>r1.my_list.append(42)
>>l1
[1, 2, 3, 42]
Quote:
>>r1.my_list
[1, 2, 3, 42]
Quote:
>>r2.my_list
[1, 2, 3, 42]
Quote:
>>>
  #5  
Old December 28th, 2006, 07:35 PM
Erik Johnson
Guest
 
Posts: n/a
Default Re: dictionary containing instances of classes behaving oddly


"Ben" <Benjamin.Barker@gmail.comwrote in message
news:1167333218.447246.236960@h40g2000cwb.googlegr oups.com...
Quote:
class record:
my_list =[]
mops=[]
>
def __init__(self,mops):
self.mops=mops
Similar to the example I gave, the lists my_list and mops shown above are
executed just once: when your class definition is first parsed.
The statement:

def __init__(self,mops):

is also executed just once, and the value for mops at that time is the value
assigned to object attributes during object construction - a reference to
record.mops, in your case. So, there are really only two lists here, class
attributes record.my_list and record.mops. Each of your constructed objects
is assigned a reference to record.mops. They all share that list. If you
want a record object to have it's own list, give it a new, empty one and
then populate it appropriately.




  #6  
Old December 28th, 2006, 07:45 PM
Ben
Guest
 
Posts: n/a
Default Re: dictionary containing instances of classes behaving oddly

Yes- I can see that my_list and mops, being outside def __init__()
only get created once, hence the confusion.

Surely def __init__() gets called each time an instance is created
however? But the snag is that if they have default values set these are
shared between all instances, even if they are, for instance, lists...?

Cheers,

Ben


Thanks.
Erik Johnson wrote:
Quote:
"Ben" <Benjamin.Barker@gmail.comwrote in message
news:1167333218.447246.236960@h40g2000cwb.googlegr oups.com...
>
Quote:
class record:
my_list =[]
mops=[]

def __init__(self,mops):
self.mops=mops
>
Similar to the example I gave, the lists my_list and mops shown above are
executed just once: when your class definition is first parsed.
The statement:
>
def __init__(self,mops):
>
is also executed just once, and the value for mops at that time is the value
assigned to object attributes during object construction - a reference to
record.mops, in your case. So, there are really only two lists here, class
attributes record.my_list and record.mops. Each of your constructed objects
is assigned a reference to record.mops. They all share that list. If you
want a record object to have it's own list, give it a new, empty one and
then populate it appropriately.
  #7  
Old December 28th, 2006, 09:25 PM
Erik Johnson
Guest
 
Posts: n/a
Default Re: dictionary containing instances of classes behaving oddly


"Ben" <Benjamin.Barker@gmail.comwrote in message
news:1167334659.073835.223040@73g2000cwn.googlegro ups.com...
Quote:
Yes- I can see that my_list and mops, being outside def __init__()
only get created once, hence the confusion.
>
Surely def __init__() gets called each time an instance is created
however? But the snag is that if they have default values set these are
shared between all instances, even if they are, for instance, lists...?
I don't think I quite understand the confusion, and I think I might have
said something misleading. The def statement itself is only executed once,
as are any object initializers contained within it. Your record.__init__()
is not using a default initializer, and here:

class record:
my_list =[]
mops=[]

def __init__(self,mops):
self.mops=mops


mops as the second argument to __init__ is a formal vairable, not a
reference to record.mops. If you pass the same list reference to each
constructor, then each record object shares the same list.

You previously said:

I had thought that then each time I created an instance of the record class
as an element of my dictionary:

self.mop_list[record_number]=record(self.mops[:])

I would create a brand new instance of the record class.It would have a
mops list initialized with mops (because the def__init__ constructor is
called when the class is instantiated), and an empty, individual list
my_list.

I beleive this is basically correct - by using the slice notation in

self.mops[:]

you are passing a copy of that list as the value. The difference is
demonstrated here:
Quote:
Quote:
Quote:
>>class Foo:
.... X = [99]
.... def __init__(self, X): # X is formal variable here, not Foo.X!
.... self.X = X
....
Quote:
Quote:
Quote:
>>y = [1,2,3]
>>f1 = Foo(y)
>>f1.X
[1, 2, 3]
Quote:
Quote:
Quote:
>>Foo.X
[99]
Quote:
Quote:
Quote:
>>f1.X.append(42)
>>f1.X
[1, 2, 3, 42]
Quote:
Quote:
Quote:
>>y
[1, 2, 3, 42]
Quote:
Quote:
Quote:
>>Foo.X
[99]
Quote:
Quote:
Quote:
>>f2 = Foo(y[:])
>>f2.X
[1, 2, 3, 42]
Quote:
Quote:
Quote:
>>y
[1, 2, 3, 42]
Quote:
Quote:
Quote:
>>Foo.X
[99]
Quote:
Quote:
Quote:
>>f2.X.append('something else')
>>f2.X
[1, 2, 3, 42, 'something else']
Quote:
Quote:
Quote:
>>f1.X
[1, 2, 3, 42]
Quote:
Quote:
Quote:
>>y
[1, 2, 3, 42]
Quote:
Quote:
Quote:
>>Foo.X
[99]
Quote:
Quote:
Quote:
>>>

So, I guess I don't see exactly where the problem is, and without all
your source, I am kinda poking in the dark. But from the behaviour observed
in your record objects, you are obviously ending up with shared list
references where you intend to get per-object individual lists. Generally
the way to do that is to assign a new, empty list in the body of the object
initializer and then populate that list as needed.

Good luck.
-ej


  #8  
Old December 28th, 2006, 10:25 PM
Steven D'Aprano
Guest
 
Posts: n/a
Default Re: dictionary containing instances of classes behaving oddly

On Thu, 28 Dec 2006 09:16:18 -0800, Ben wrote:
Quote:
Hello...
>
I have a dictionary, where each value is a seperate instance of the
same class:
>
self.mop_list[record_number]=record(self.mops[:])
Others have already solved the immediate problem, but I'd just like to
make a brief comment about self-documenting code, in particular misleading
self-documenting code.

The O.P. says he has a DICTIONARY called mop_LIST.

[raises eyebrow]



--
Steven.

 

Bookmarks

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are Off
[IMG] code is Off
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On

What is Bytes?

We are a network of experts and professionals in IT and software development that help one another with answers to tough questions and share insights. Get the best answers to your questions from over network members.
Post your question now . . .
It's fast and it's free

Popular Articles