initializing mutable class attributes

Larry Bates lbates at swamisoft.com
Mon Aug 30 11:02:40 EDT 2004


Dan,

I too use class attributes to assign defaults, but do
it like following:

import copy

    class Father:
        _attr1default=None
        _attr2default=[]

        def __init__(self):
            self.attr1=self._attr1default
            # Get copy of attr2default
            self.attr2=list(self._attr2default)

         def foo(self, data):
             self.attr1=data
             self.attr2.append(data)


     class Child (Father):
         def __init__(self):
             Father.__init__(self)
             #
             # At this point self.attr1 (instance)
             # and self.attr2 (instance) hold their defaults
             # while _attr1/_attr2default (class) still hold
             # their default values for initialization of more
             # class instances.
             #

HTH,
Larry Bates
Syscon, Inc.


"Dan Perl" <dperl at rogers.com> wrote in message
news:sHGYc.93306$pTn.42032 at news01.bloor.is.net.cable.rogers.com...
> I will clarify something that was probably not clear enough in my initial
> posting.  I am interested in instance attributes, but I am using the class
> attributes to provide a default, "null", value for the instance
attributes.
> Yes, the instance attributes only mask the class ones, but a class
attribute
> and an instance attribute can be used like this:
>     class WorksForMe:
>         attr=None        # used just as a default value for the instance
> attribute self.attr
>         def foo(self):
>             self.attr=SomethingUseful( )
>         def bar(self):
>             if self.attr:
>                 useIt(self.attr)
>             else:
>                 ignoreIt(self.attr)
> This makes it safe for an instance of WorksForMe to invoke bar( ) even if
it
> never invoked foo( ).
>
> "Benjamin Niemann" <b.niemann at betternet.de> wrote in message
> news:cgul4v$h1d$1 at online.de...
> > That's the way it is supposed to work. Instance attributes have to be
> > initialized via self.foo=..., usually in __init__() which in turn is
> > *STRONGLY* advised to class its parents __init__() - or you create
> > instance attributes 'on-the-fly' when they are used for the first time
> > (useful technique for mixin classes without constructor). Class
> > attributes are initialized once for the class and are shared between
> > instances.
>
> You are confirming the code I suggested but you don't share my view that
> such code is awkward.  I think I I was actually conservative calling it
> awkward, I would rather call it unsafe.  If I were a third-party library
> vendor, I would not be comfortable providing a mixin class that forces
users
> to either invoke the parent's __init__ in their constructors or to
> initialize the instance attributes on-the-fly.  The latter would even be
> against the principles of encapsulation, users should not need to know
about
> the parent's attributes, especially because they may change in future
> releases.  Both ways of restricting the use of the mixin class are unsafe
> because they are easy to be ignored by users.  And it is not only the
users'
> fault if they do not follow the restrictions, it is also my fault to put
> such restrictions in the first place.
>
> I think this points to a weakness in Python as an OO language.  I'm not
> trying to bash it, but my understanding is that Python is still evolving
in
> that respect and I think that this should be improved in the future.
Then,
> on the other hand, maybe I'm the only one feeling this way and there's not
> going to be a change.
>
> > "self.attr1=data" in Father.foo() doesn't "override" the Father.attr1
> > attribute you defined before. It creates an instance attribute that
> > shadows Father.attr1!
> > Both attribute assignments in Father are OK - if you treat them as class
> > attributes. They won't become instance attributes by hidden magic.
> >
> > Dan Perl wrote:
> > > There is something with initializing mutable class attributes that I
am
> > > struggling with.  I'll use an example to explain:
> > >     class Father:
> > >         attr1=None   # this is OK
> > >         attr2=[ ]        # this is wrong
> > >         def foo(self, data):
> > >             self.attr1=data
> > >             self.attr2.append(data)
> > > The initialization of attr1 is obviously OK, all instances of Father
> > > redefine it in the method foo.  But the initialization of attr2 is
wrong
> > > because all the instances of Father end up sharing the same value.
> Maybe
> > > that is desired sometimes, but usually it is just a bug.
> > >
> > > So the only solution I see to this is to initialize attr2 in __init__:
> > >     class Father:
> > >         attr1=None
> > >         def __init__(self):
> > >             self.attr2=[ ]
> > >
> > > This is already awkward because there is such a difference between
attr1
> and
> > > attr2.  But moreover, I think this forces subclasses of Father to do
> > > something like this:
> > >     class Child (Father):
> > >         def __init__(self):
> > >             Father.__init__(self)
> > >             self.attr3=[ ]
> > >
> > > I find this even more awkward because many people will forget to do
it.
> > > Clearly, this is then a more general issue with __init__, but I think
it
> is
> > > accentuated by the fact that you HAVE TO HAVE __init__ in order to
> > > initialize attributes that are mutable.
> > >
> > > Is there something I don't know here and there is a better way to do
> this in
> > > Python?  I would like to get a better solution or otherwise start a
> > > discussion.
> >
>
>





More information about the Python-list mailing list