dictionary as attribute of a class...

T

tinauser

Hallo list,
here again I have a problem whose solution might be very obvious, but
I really cannot see it:
I have a class having as attribute a dictionary whose keys are names
and values are instance of another class.
This second class has in turn as an attribute a dictionary.
I want a function of the first class that can change value of one of
the second class instance's dictionary.
however I cannot do it without modifying this attribute for ALL the
instance of the second class contained in the first class' dictionary.
What I'm doing wrong?

the code:

###############
###can i change a dictionary attribute of an instantated object
without affectin all the instances of that object?

class mistClass():
def __init__(self,name,cDict={}):
print 'mistClass ',name,' Init'
self._name=name
self._cDict=cDict

def setName(self,n):
self._name=n

def getName(self):
return self._name

## def setDict(self,one,two):
## self._cDict['one']=one
## self._cDict['two']=two
def setDict(self,listK,listV):
assert len(listK)==len(listV)
for k,v in zip(listK,listV):
self._cDict[k]=v

def getDict(self):
return self._cDict

class mistClassContainer():
def __init__(self,name,dict_of_mistclass={}):
print 'init mistClassContainer ',name
self._name=name
self._DOM=dict_of_mistclass

def add_mistclass(self,mc):
for el in mc:
self._DOM[el]=mistClass(el)

## def mod_mistclasscDict(self,mc,one,two):
## self._DOM[mc].setDict(one,two)
def mod_mistclasscDict(self,mc,lK,lV):
self._DOM[mc].setDict(lK,lV)

a=mistClassContainer('firsmistclasscontainer')
a.add_mistclass(['mc1','mc2','mc3','mc4','mc5','mc6'])
print 'before modification'
for el in a._DOM.iterkeys():
print a._DOM[el].getDict()
print a._DOM[el].getName()

a.mod_mistclasscDict('mc1',['one','two'],['modone','modtwo'])
print 'after modification'
for el in a._DOM.iterkeys():
print a._DOM[el].getDict()
print a._DOM[el].getName()

b=mistClass('mc7')
print b.getDict()
print b.getName()
b.setName('modified name')
b.getName()

for el in a._DOM.iterkeys():
print a._DOM[el].getName()
 
B

Benjamin Kaplan

Hallo list,
here again I have a problem whose solution might be very obvious, but
I really cannot see it:
I have a class having as attribute a dictionary whose keys are names
and values are instance of another class.
This second class has in turn as an attribute a dictionary.
I want a function of the first class that can change value of one of
the second class instance's dictionary.
however I cannot do it without modifying this attribute for ALL the
instance of the second class contained in the first class' dictionary.
What I'm doing wrong?

This is one of the biggest gotchas in Python. Default arguments are
only evaluated *once*, when the function/method is declared. Not every
time the function is called. Every instance of mistClass that didn't
specify a separate cDict gets the same object as its cDict. The
solution is to use a sentinel value (either None or a single object
and use an "is" comparison) and create a new dict in the constructor
if the default argument is still the sentinel.
class mistClass():
   def __init__(self,name,cDict={}):
       print 'mistClass ',name,' Init'
       self._name=name
       self._cDict=cDict

should be changed to

sentinel = object()
class mistClass :
def __init__(self, name, cDict=sentinel) :
print 'mistClass ',name,' Init'
self._name=name
if cDict is not sentinel :
self._cDict=cDict
else :
self._cDict = {}

class mistClassContainer():
   def __init__(self,name,dict_of_mistclass={}):
       print 'init mistClassContainer ',name
       self._name=name
       self._DOM=dict_of_mistclass

and do the same thing with this one.
 
P

Peter Otten

tinauser said:
Hallo list,
here again I have a problem whose solution might be very obvious, but
I really cannot see it:
I have a class having as attribute a dictionary whose keys are names
and values are instance of another class.
This second class has in turn as an attribute a dictionary.
I want a function of the first class that can change value of one of
the second class instance's dictionary.
however I cannot do it without modifying this attribute for ALL the
instance of the second class contained in the first class' dictionary.
What I'm doing wrong?

the code:

###############
###can i change a dictionary attribute of an instantated object
without affectin all the instances of that object?

class mistClass():
def __init__(self,name,cDict={}):

When you don't provide a cDict argument the default is used which is the
same for every instance. Change the above to

def __init__(self, name, cDict=None):
if cDict is None:
cDict = {}
class mistClassContainer():
def __init__(self,name,dict_of_mistclass={}):

Same here.
def setName(self,n):
self._name=n

def getName(self):
return self._name

Python has properties, so you don't need this just-in-case getter/setter
nonsense.
for k,v in zip(listK,listV):
self._cDict[k]=v

Make that

self._cDict.update(zip(listK, listV))

By the way, not everyone loves Hungarian notation...
 
T

tinauser

tinauser said:
Hallo list,
here again I have a problem whose solution might be very obvious, but
I really cannot see it:
I have a class having as attribute a dictionary whose keys are names
and values are instance of another class.
This second class has in turn as an attribute a dictionary.
I want a function of the first class that can change value of one of
the second class instance's dictionary.
however I cannot do it without modifying this attribute for ALL the
instance of the second class contained in the first class' dictionary.
What I'm doing wrong?
the code:
###############
###can i change a dictionary attribute of an instantated object
without affectin all the instances of that object?
class mistClass():
    def __init__(self,name,cDict={}):

When you don't provide a cDict argument the default is used which is the
same for every instance. Change the above to

def __init__(self, name, cDict=None):
    if cDict is None:
        cDict = {}
class mistClassContainer():
    def __init__(self,name,dict_of_mistclass={}):

Same here.
    def setName(self,n):
        self._name=n
    def getName(self):
        return self._name

Python has properties, so you don't need this just-in-case getter/setter
nonsense.
        for k,v in zip(listK,listV):
            self._cDict[k]=v

Make that

self._cDict.update(zip(listK, listV))

By the way, not everyone loves Hungarian notation...

Thanks both for the reply, I'll take some time to digest so to avoid
further error in the future.Thanks again.
 

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,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top