Copy constructors

Guido van Rossum guido at python.org
Mon Aug 13 09:03:31 EDT 2001


"Alex Martelli" <aleaxit at yahoo.com> writes:

> > For example, you could have a __getattr__ that initialized the thing
> > as soon as it is touched.
> 
> But then *none* of the methods could belong to the class?!  Each and
> every one to be inserted afresh in every instance's __dict__?!

No, in the new system, __getattr__ is called for all attributes.  See
my response to Roman.

> But then
> what's the use of "making the object the right class from the start",
> as that class C HAS to be empty to let __getattr__ do its job?!
> 
> Of course, if the initialization is done by __getattr__ anyway, it's
> quite futile to use __new__ to "return an empty instance of the
> class" -- the necessarily-empty __init__ does just as well, no?

Sorry, I'm not following you at all here.  I suggest that you try
again.

The specific example *I* was thinking of is in pickle.py, which wants
to create an instance of a class without calling __init__.  It
currently uses this:

    value = _EmptyClass()
    value.__class__ = klass # The class it should be

and then it initializes the instance variables.

I claim that it's more elegant to write

    value = klass.__new__()

instead.

> So, again, I ask -- how is knowing from the start the class C to
> which the instance will belong, when its Promise is fulfilled, and
> exploiting the __new__ feature to make an empty C.__new__ -- how
> does this *HELP AT ALL*?  Your alleged "example" is NOT an example
> of all of this glittering technology helping at all with this
> problem.

Zope's persistency support manages this without assignment to
__class__.  A persistent object has three states: ghost, valid, and
modified (I think the names are different).  A ghost object has the
right class, but no instance variables; these are loaded on demand,
and then the state changes to valid.  On the first change to an
instance variable, the state changes again to modified.  When a
modified object is written to the store, it is changed back to valid;
when a valid object is no longer needed, its instance variables are
deleted and the state changed back to ghost (usually it will be
garbage collected next, but if there is still a reference to it, it
may be resurrected from the store later).

> Which is not a problem in Python as it stands -- becomes a problem
> if and when you implement the "enhancement" (?) of forbidding the
> change-class-of-object idiom that Python now supports.

I really doubt that Python 1.4 was a much worse language than 1.5, and
I doubt that Python's popularity has much to do with the ability to
assign to __class__.

Besides, I'm not so much forbidding it as resisting the work it takes
to implement safely.  You can write a metaclass that allows __class__
assignment in C, and then its safety is your own responsibility.

[snip]
> But it's ironic -- there, I used an indirector to work around the
> inability of inheriting from a built-in object.  Now, I look forward
> to pensioning off that idiom... and I may have to resurrect it to work
> around the inability of changing an object's __class__...!-)

I'd like to see which is more common -- the need to change __class__
or the need to inherit from a built-in type.  I'm betting the latter,
by a large amount.

> I guess I'll have to look at the source to understand why that's
> so inevitable -- right now it escapes me.  (Is it going to be part
> of 2.2alpha2, or do I have to get a CVS tree?)

The architectural restrictions that make it hard to change __class__
in some situations have been part of Python since it was first
released.  Unless I misunderstand what you're asking for, 2.2a1 should
exhibit this just fine.

> Of course, just as there are other ways of accomplishing raising-to-
> power, besides having it as a built-in -- it IS just repeated
> multiplication, after all.  That's no argument for removing **
> from the language, it seems to me.  It IS no doubt rarely used
> AND easily mis-used [code such as x**3+2.2*x**2+1.4*x+3.6
> rather than 3.6+x*(1.4+x*(2.2+x)) is most likely slower] -- but
> that's no real argument for taking ** away, as it may well be the
> most natural/clear/readable way to express some problems, and
> also (if and when used appropriately) faster than alternatives.

This is the most bizarre argument for __class__ asignment that I have
seen so far.

> As I said, exactly Stroustrup's reasoning in C++'s design -- a non
> overridable method is faster than a virtual one, so he preferred to
> make users request virtuality explicitly.  Like anybody who's ever
> taught C++ or helped beginners in that language fix mistakes, I've
> had occasion to bemoan that design choice repeatedly -- even though,
> with performance such an important priority for C++, and historical
> compatibility reasons, it's quite understandable.

Since you're invoking beginners here, let me bounce that argument
right back.  Do you seriously believe that assignment to __class__ is
something you would want beginners to know about?

> > I expect that the new facilities will be seriously user-tested only
> > after 2.2 is released, and experience will learn how often people are
> > changing class variables.
> 
> You think people will be changing class variables _less_ often than
> now because of 2.2's new facilities?  I don't see the relevance, but
> I guess I must have missed something.  The new facilities appear
> to be very deep and important, but in areas quite different from
> those in which class-object changes are useful, it seems to me.

Your mind works so different from mine...  It's frustrating for me to
try and understand what you mean, and no doubt it's the same for you.

I strongly believe that most Python users have no need for assignment
to class attributes most of the time.  Class attributes are mainly
used for two purposes: (1) methods and (2) default initializations of
instance variables.  Neither use requires changing the class
attribute.  Overrides are done using subclassing or assignment to
instance variables.  I know some people like to use class variables
instead of module globals, mimicking Java/C++ static class variables,
but I believe that's mistaken -- those languages don't have a module
namespace like Python, so the convention of putting globals in a class
makes sense from a naming perspective there.

Every time someone uses the dynamism to patch a standard library
class, I cringe -- it's asking for trouble.

--Guido van Rossum (home page: http://www.python.org/~guido/)



More information about the Python-list mailing list