dictionary as attribute of a class...

Discussion in 'Python' started by tinauser, Jan 5, 2011.

  1. tinauser

    tinauser Guest

    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()
     
    tinauser, Jan 5, 2011
    #1
    1. Advertising

  2. On Wed, Jan 5, 2011 at 10:07 AM, tinauser <> wrote:
    > 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.
     
    Benjamin Kaplan, Jan 5, 2011
    #2
    1. Advertising

  3. tinauser

    Peter Otten Guest

    tinauser wrote:

    > 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...
     
    Peter Otten, Jan 5, 2011
    #3
  4. tinauser

    tinauser Guest

    On Jan 5, 4:34 pm, Peter Otten <> wrote:
    > tinauser wrote:
    > > 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.
     
    tinauser, Jan 5, 2011
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ilias Lazaridis
    Replies:
    6
    Views:
    444
    Ilias Lazaridis
    Feb 21, 2006
  2. james_027
    Replies:
    1
    Views:
    329
    Marc 'BlackJack' Rintsch
    Aug 22, 2007
  3. Navkirat Singh
    Replies:
    6
    Views:
    3,075
    Navkirat Singh
    Jul 29, 2010
  4. Chris Rebert
    Replies:
    0
    Views:
    529
    Chris Rebert
    Jul 29, 2010
  5. Fox

    dictionary within dictionary

    Fox, Mar 8, 2005, in forum: ASP General
    Replies:
    5
    Views:
    194
    Michael D. Kersey
    Mar 13, 2005
Loading...

Share This Page