sharing dictionaries amongst class instances

sharing dictionaries amongst class instances

Post by Kerry Neil » Tue, 11 Nov 2003 05:22:36


Hi,
Really hung up on this one. I'm trying to get all the fields of a
dictionary to be unique for each class:

class A {
my_dict = []
dict_entry = { 'key1':0, 'key2':0 }

__init__(self):
for x in range(10):
tmp = copy.deepcopy(self.dict_entry)
tmp['key1'] = x
self.my_dict.append(tmp)
}

in a driver, I have

inst0, inst1 = A.A(), A.A()
inst0.my_dict[1]['key2'] = "ted"
inst1.my_dict[5]['key2'] = "steve"
inst0.display()
inst1.display()

printing them out shows that both objects have ted and steve in their
dictionaries. I have done this very thing outside of a class, and it works
wonderfully. All other attributes in the class are able to remain unique.
ie, inst0.data = 5 and inst1.data = 8 works fine.
I believe I could set the dictionaries up beforehand, but they will be
substatially different sizes, and it certainly wouldn't be proper.

Any ideas? Thanks very much for any insight.
 
 
 

sharing dictionaries amongst class instances

Post by Peter Otte » Tue, 11 Nov 2003 06:23:15


class A { ... } is *not* Python. Are you converting from Java :-) ?
From what follows, I conclude that you want the dicitonary to be unique for
each *instance* (if you want it unique for the class, you are already
there). Unlike Java, you must put it in the constructor then (untested):

class A:
def __init__(self):
self.my_dict = {"key1": 0, "key2": 0}

Dictionaries are the {} thingies, [] indicate list literals. Deepcopy should
be buried very deep in the documentation, where no newbie will ever find
it...
Seriously, take the time to read the excellent tutorial that comes with
Python, and only then try to clean up this mess.

Peter

 
 
 

sharing dictionaries amongst class instances

Post by Andy Jewel » Tue, 11 Nov 2003 06:45:00


Kerry,

two observations:

1) That's not proper Python! ;-) and 2) I think the behaviours you want are
only available in 'new style' classes, i.e. classes based upon 'object'. Did
you mean:

---8<---
class A(object):
my_dict = []
dict_entry = { 'key1':0, 'key2':0 }

def __init__(self):
for x in range(10):
tmp = copy.deepcopy(self.dict_entry)
tmp['key1'] = x
self.my_dict.append(tmp)
---8<---

A.my_dict is a /class variable/, i.e. it is tied to the class, not the
instance - there's only one of them, viz:

---8<---
(1083256236, 1083254732)
(1083253228, 1083253228)
True
---8<---

If you move the initial assignment of my_dict into the __init__() procedure,
and call it self.my_dict() instead, then you'll get a new instance of a list
each time - maybe this is what you want. BTW, is there any particular reason
for choosing the word 'my_dict' to describe a list?

hope this helps you arrive at a solution ;-)

-andyj
 
 
 

sharing dictionaries amongst class instances

Post by Kerry Neil » Tue, 11 Nov 2003 07:02:18

> class A { ... } is *not* Python. Are you converting from Java :-) ?
for
should


hmm ... I didnt' word this quite right. I want a list [] of dictionaries
{}. I mean for it to be similar to an array of structs in C, only using a
dictionary instead of a struct and a list instead of an array. Seem
reasonable?

I have read the entire tutorial as well as "Learning Python" in its utter
entirety. This is precisely how I know of deepcopy. I noticed that when I
appended dictionaries to my list, modifying one modifed them all. I want
each entry to be unique. I don't see how to do this without deepcopy. What
really confuses me is that this same scenario works when not embedded in a
class.

As for your suggestion, putting the dictionary initialization and the list
in the contructor did the trick. I had this:

class a:
x = 0
y = 0
:

I suppose it's a c++ leftover thing, thinking i had to declare before I
init. I don't yet understand why it's different for a simple data type than
it is for the list of dictionaries. But by taking the dict_entry{} and
my_dict[] out of the top of the class, it works without deepcopy. Thanks
for the help.
 
 
 

sharing dictionaries amongst class instances

Post by Kerry Neil » Tue, 11 Nov 2003 07:07:18


Kerry,

two observations:

1) That's not proper Python! ;-) and 2) I think the behaviours you want are
only available in 'new style' classes, i.e. classes based upon 'object'. Did
you mean:

---8<---
class A(object):
my_dict = []
dict_entry = { 'key1':0, 'key2':0 }

def __init__(self):
for x in range(10):
tmp = copy.deepcopy(self.dict_entry)
tmp['key1'] = x
self.my_dict.append(tmp)
---8<---

A.my_dict is a /class variable/, i.e. it is tied to the class, not the
instance - there's only one of them, viz:

---8<---
(1083256236, 1083254732)
(1083253228, 1083253228)
True
---8<---

If you move the initial assignment of my_dict into the __init__() procedure,
and call it self.my_dict() instead, then you'll get a new instance of a list
each time - maybe this is what you want. BTW, is there any particular
reason
for choosing the word 'my_dict' to describe a list?

hope this helps you arrive at a solution ;-)



Thanks for the reply, Andy.
Your observation was correct, as I also learned from Peter, and moving the
initial assignment into __init__ is whta I wanted. I guess I didn't realize
that one could do that, being more familiar with c++. And no, calling a
list my_dict was pure accident. Perhaps my explanation in response to Peter
explains it a bit better.

Thanks.
 
 
 

sharing dictionaries amongst class instances

Post by Francis Av » Tue, 11 Nov 2003 07:11:29

"Kerry Neilson" < XXXX@XXXXX.COM > wrote in message
news:gmxrb.114011$275.322447@attbi_s53...

I don't really understand what you're trying to do here, and it doesn't help
that the syntax is completely wrong. Try pasting directly from real code or
an interactive session in the future, and not trying to ad-lib an email
message.

I assume you mean this (watch me break my own advice):

import copy
class A:
dictlist = []
dictlist_elem = { 'key1':0, 'key2':0 }

def __init__(self):
for x in range(10):
tmp = copy.deepcopy(self.dictlist_elem)
tmp['key1'] = x
self.dictlist.append(tmp)


Now, this code makes no sense to me without knowing what you want to do.
Init will just keep adding similar dictionaries to dictlist, which are
accessable from all instances.

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Is this what you want?


So, class A is now in a module named A? And what does A.A.display()
display? (You didn't include code for that method).

I'll assume that the module detail is insignificant, and that display()
prints dictlist.


Well, yes. You declared your dictionary and dictionary lists as class
attributes. Each instance does a lookup in itself, and not finding
'dictlist' it looks in the class, where it's found.

Ok, this point can often trip people up, so I'll go into more detail. (The
following is for "classic" classes, which are on their way out. New-style
classes are a bit different wrt instantiation and type.)

In Python, classes are objects. So when you define class C, what you're
saying is "make a class object which has these attributes and these methods,
and make the name 'C' point to that object."

... someint = 12
... mylist = [1,2,3]
...
<class __main__.C at 0x00AC5600>
12
[1, 2, 3]

See? It's a real object with a real location in memory, not just a
"template" for "real" instances. Classes are just as real as instances.

When you make an instance, Python makes a new object (an instance) and then
calls C.__init__(newinstanceobject). Init is an instance
configurator--anything done in init is only done in the instance, not in the
class.

Indeed, all instances use the class's methods. instanceobject.dosomething()
is really C.dosomething(instanceobject) (where C is determined at runtime,
as the derived class which provides the method in question, after
inheritence is taken into consideration). The "self" you add to each method
object is the stand-in argument which will be the instance itself.

Now, if you don't keep the above in mind, behavior like this becomes
shocking:
12
0
12
[1, 2, 3, 5]
[1, 2, 3, 5]
[1, 2, 3, 5]

When you do assignment on an instance, you are adding an attribute *to the
instance*, not looking up that attribute in the instance/class hiearchy.
But when you *modify* an attribute, Python *does* look for that attribute,
does find it in the class object, and does modify it in the class object,
*not* in the instance object!

Assignment is fundamentally different from modification. Assignment makes a
name point to an object. mylist[2] = 'something' makes the third item in
mylist (an un-named name, if you will) point to 'something'. But
mylist.dosomething() is radically different! It changes the object *in
place*. Just to make a
 
 
 

sharing dictionaries amongst class instances

Post by bokr » Tue, 11 Nov 2003 07:56:46


Please post something that at least compiles

>>> class A {
File "<stdin>", line 1
class A {
^
SyntaxError: invalid syntax


^--this must be left over from some abortive experiment
This looks like you are not showing an import A, assuming that class A is defined in A.py

I suggest you copy and paste from the session where you did that. Otherwise
you're wasting your time and everyone else's.

The above doesn't work period, so there is no telling what you actually did,
and I might be able to guess what you are trying to do, but I don't really want to, sorry.

See above, guess I need a snack ;-)

Regards,
Bengt Richter
 
 
 

sharing dictionaries amongst class instances

Post by Peter Otte » Tue, 11 Nov 2003 21:41:42


class A:
x = 100
y = {}

Here both assignments aren't declarations, but statements that are executed
when the module containing them is imported.

(100, {})

So they are both stored in the class. Let's play a little:

100

(200, 100)

You might suppose that a.x was initialized to A.x, but that's not the case:

100

See? The old value seems to reappear. When you say a.x and there is no
instance attribute, Python looks up the class attribute with the same name.
So you can use the class attribute as a kind of default value for the
instance attribute.
But beware, this technique bites you as soon as you try it with mutables:


This looks the same, whether y is an instance or class attribute, and you
would not complicate client code with some detection scheme.

{'key': 'value'}

Oops, there was no y attribute in the instance, so we inadvertently changed
y of the underlying class.

By the way, for the same reason you must not use mutable values as default
function arguments:

def addwords(words, wordlist=[]):
"Bad, don't do it"
wordlist.extend(words.split())
return wordlist

The default wordlist is growing every time you don't provide a second
argument. The canonical Python solution is

def addwords2(words, wordlist=None):
if wordlist is None: wordlist = []
wordlist.extend(words.split())
return wordlist

which creates a new wordlist when the second argument is omitted.

Peter
 
 
 

sharing dictionaries amongst class instances

Post by Kerry Neil » Thu, 13 Nov 2003 14:42:10

> See? The old value seems to reappear. When you say a.x and there is no
name.
changed

Thank you. Your message really cleared a lot of things up for me.