469,282 Members | 1,732 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,282 developers. It's quick & easy.

initializing mutable class attributes

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.
Jul 18 '05
50 5679
Alex:
#include "Base.h"

int foo = 23;
class Derived: public Base {
public:
Derived() { foo = 45; }
};

Is this code correct? Sure, it compiles and runs perfectly using Base
version 12.3. Then Base comes out with version 12.4 and this does not
compile any more. Why? Because the new version of Base has added a
private member named foo.


My C++ skills are rusty and old. I had to experiment
with this to understand what was going on. I had thought
that private: kept the above from happening. Now I know
better.

I was wondering though about the justification of
"is this code correct" using "compiles and runs perfectly"
under a given circumstance. That justification has
been applied to many incorrect pieces of code, including

#define SQUARE(x) ((x)*(x))

only to be proven wrong in the real world. Part
of learning the language is learning about these
gotchas and acquiring the skills needed to do it
correctly.
The problem in your example is that variable lookup
occurs first in class then in static scopes. I can
tell the compiler to only use static scope, as in

Derived() { ::foo = 45; }

Based on my creaky memories, this shouldn't have
the same problems. Does it have others? And is
this this proper and accepted solution, meaning
that I should always write an explicit static
scope when I want to ensure I don't accidently
conflict with future changes to the base class?

Andrew
da***@dalkescientific.com

P.S.
Congratulations to the both of you!
P.P.S.

Is the modern implementation of that DOUBLE macro
something like

inline template<T>
T& DOUBLE(const T& x) {
return T*T;
}

? I don't think so since it doesn't do coercion
the same way. Consider
float f = .... ;
double x = SQUARE(f);

The f*f gets promoted to double. The macro version
assigns the double to a double so keeps the precision.
OTOH, the template version narrows the double to
a float (for the return value) then widens that
float back to a double, hence loosing precision in
the process.
Jul 18 '05 #51

This discussion thread is closed

Replies have been disabled for this discussion.

By using this site, you agree to our Privacy Policy and Terms of Use.