initializing mutable class attributes

Dan Perl dperl at rogers.com
Mon Aug 30 16:19:04 CEST 2004


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