initializing mutable class attributes
aleaxit at yahoo.com
Tue Aug 31 18:19:33 CEST 2004
Dan Perl <dperl at rogers.com> wrote:
> > > 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.
> > > 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.
I may not have enough experience with beginners, I guess -- my wife,
Anna, does have it, and I hope she sees this tidbit and shares that
experience with us. In my limited experience with beginners, in a huge
variety of programming languages and other technologies, they make every
possible mistake and many that are patently impossible too; and if you
try to design your technology to be foolproof, you're wasting your time,
because fools are _extremely_ ingenious. I prefer simplicity and
transparency over desperate attempts to safe fools from their
foolishness -- the smaller, simpler and more transparent a language or
other technology is, the earlier beginners cease to be beginners and
stop making most of their earlier, incredible mistakes.
> > > This is already awkward because there is such a difference between attr1
> > > 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__.
Yes, because immutable attributes cannot be mutated -- only by rebinding
that name will anything change, and name rebinding never affects the
object that name previously referred to. But mutable attributes can be
mutated, indeed that's the whole point of having them, rather than just
having their names rebound to refer to other objects. I know you want
some kind of automatic copy of (some?) class attributes to instance
attributes, but I think you just haven't thought clearly enough about
the issues involved, even something as trivial as whether the copy
should be shallow or deep -- the difference will be enormous.
> > > 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
Sure! If they devoted their energy to understanding things in depth and
complete detail, rather than campaigning to change something because
they don't understand that something well enough yet, their adjustment
would be less difficult and we'd all be happier, of course. But human
nature will always make some people perceive that requiring THEM, their
precious and unique SELVES!, to change (their habits, their minds, etc)
is absurd, while it's obviously all the rest of the universe that has to
change to accomodate their tastes and preferences (that may be a
disaster for millions of existing users, but hey, none of those users is
THEM, so they're obviously not very important). They don't generally
phrase things that way (too politically incorrect) and more often than
not they rationalize even to themselves the changes as being good for
mankind, but, really, they're generally just sticking up for their
existing attachments, habits, and worldviews. I'm quite prone to doing
it myself unless I keep up a substantial guard against my own laziness
-- so I try to avoid suggesting any changes in something complex, if I
possibly can avoid that, until and unless I convince myself that I have
a thorough, complete understanding of that something, of the reason for
being and consequences of what I'm thinking of changing, and of the
impact and consequences of what I'd like to change it into.
> '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
It frightens me to consider that Python might one day get designs
decisions made, not because GvR sees them as useful in themselves and
consistent with Python's overall workings, but to "accomodate" people
who are not (yet) familiar with Python. Fortunately I can generally
dispell the fear and calm down, but please don't ask me to consider such
horrid scenarios, they can do nothing but frighten me uselessly.
> 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.
In this like in many other details, Python chooses simplicity and
clarity against automatic, black-magic, "behind the scenes" approaches.
"Explicit is better than implicit" is one part of the Zen of Python that
speaks to this -- at a python interactive prompt do
to read it all. The automatic invocation of default constructors when
they exist, what you have to do instead to get different constructors
for parent classes, etc etc, are all complications. When classes are
designed to execute responsibilities it's not unusual that they can't
really have a useful no-arguments constructor -- and when they don't
have such a constructor, C++'s and Java's rules are nothing BUT overhead
and conceptual complication. In C++ one often works around the burden
of contraints on constructor calls via "two-phase constructors" -- a
default constructor that does not really leave the instance in a usable
state, just to bypass the darn rules you find "have some clear
advantages", and then a normal member function that really does the job
of initialization and has the enormous advantage that YOU decide when
and with what arguments to call it, without all the darn rules in the
way, explicitly. Well, in Python the constructor, __init__, is under
you control in exactly this way -- less complication, more simplicity,
more transparency, fewer rules to learn, and far fewer instances of the
"two-phase constructor" pattern (not zero, mind you -- just 99% fewer).
> Those are my 2 cents.
> 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.
I don't think you need to worry about this!-)
More information about the Python-list