initializing mutable class attributes

Dan Perl dperl at rogers.com
Mon Aug 30 11:39:54 EDT 2004


"Alex Martelli" <aleaxit at yahoo.com> wrote in message
news:1gjc8cs.sqvo1v1fhabdjN%aleaxit at yahoo.com...
> Dan Perl <dperl at rogers.com> 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.
>
> I disagree: good Python programmers often use mutable class attributes,
> and use them to good effect.  I've done my share of Python teaching,
> consulting and mentoring, and I definitely do *not* think this usage "is
> desired sometimes but usually it is just a bug".

My mistake.  I shouldn't have made that statement.  I don't really know
which case happens more often.  Having said that, that is probably a mistake
that many beginners make.  Okay, I have no real way of knowing that either,
but I think it's a good assumption.

> > 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 the canonical way, sure.
>
>
> > This is already awkward because there is such a difference between attr1
and
> > attr2.
>
> One is a class attribute (which nobody forced you to have), the other is
> an instance attribute.  If you want both to be instance attributes,
> initialize both in __init__ -- that's all there is to it.  Don't use
> class attributes unless there's a reason for them to be class
> attributes, that seems like a good and sensible rule of thumb to me.

I was using the class attribute as a default, "null", value for the instance
attributes.  That works just fine for immutable attributes and it allows me
not to implement an __init__.

> >  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=[ ]
>
> Assuming an instance of Child needs to have both attributes attr2 and
> attr3, yes.
>
> >
> > I find this even more awkward because many people will forget to do it.
>
> Forget to do what -- call the parent class's __init__?  Again, this is
> rare -- not as rare as the other "usually just a bug" you opined about,
> but not common.  A class normally needs __init__ for a large number of
> purposes, of course, not just to assign mutable attributes to each
> instance, therefore people who learn subclassing do learn to call the
> parent class __init__ very early on, to avoid everything breaking.
>
> > 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.
>
> Making __init__ more common means people are more likely to get used to
> it, and thus makes the bug of not calling a parent class's __init__
> rarer, not "accentuated".

I'm leaving the rest of your reply out, but thanks for the suggestion of a
metaclass, I'll look into it.

After seeing a few replies (yours, Benjamin Niemann's and Peter Otten's) to
my initial posting, I think I am getting the picture that there is a
conscious decision to keep the use of __init__ the way it is and just make
people learn it and learn it early enough.  That's a valid approach and I'll
accept it.

I can also understand your frustration with people who are new to Python,
like me, coming from a background in other OO languages, who are not yet
comfortable with "the Python way" and feel that there is a "better way" and
who suggest changing Python.  But you also have to be reallistic and accept
that there will always be people coming to Python from other languages and
that the adjustment is rather difficult in some areas.  You may just say
'Tough!', or you may help them to make that adjustment (I think you are
doing that), or you may even accommodate them (you should at least consider
that).

No one, including you, has given me a reason WHY __init__ is implemented
this way.  I am not bashing you for that, I would just still like to hear
that 'WHY'.  I'm sure that this implementation has some advantages.  But,
coming from a C++ and Java background, where parent default constructors are
automatically invoked (well, not always, and that is something that users
have to learn too), I find that that approach has some clear advantages.

Those are my 2 cents.

Dan
PS: Does my last name attract the wrong kind of attention from people in
this newsgroup?  It's really my name, it's not fake, BTW.





More information about the Python-list mailing list