Copy constructors

Alex Martelli aleaxit at yahoo.com
Sat Aug 11 05:37:36 EDT 2001


"Guido van Rossum" <guido at python.org> wrote in message
news:cp66bv46jk.fsf at cj20424-a.reston1.va.home.com...
    ...
> While I probably introduced this myself (pickle uses it), I have one
> reservation.  Assignment to self.__class__ is unique to Python -- it's
> not an idiom one can easily translate to other languages.  It's also a
> relatively new Python feature (I don't even know if Jython supports

Yep, no problems:

D:\jython>jython
Jython 2.0 on java1.3.0_02 (JIT: null)
Type "copyright", "credits" or "license" for more information.
>>> class X: pass
...
>>> x=X()
>>> x
<__main__.X instance at 4848023>
>>> class Y: pass
...
>>> x.__class__=Y
>>> x
<__main__.Y instance at 4848023>
>>>

I believe Ruby and Perl both have the powerful (if rarely used)
"change class dynamically" feature.  It would be a pity if Python,
which introduced it, were now to lose it.  A similar feature was a
*hair-breadth away* from making it into early C++, according
to Stroustrup's "Design and evolution" book -- he seriously
considered the possibility of an object referring to its own
'base-object' via a pointer (as is done in virtual inheritance)
with the ability to change that pointer in the fly (leading to a
recomputation of virtual tables) -- he eventually gave it up,
with some regrets, for performance considerations (possibility
of 100%-performance being always a high priority in C++'s
evolution -- specifically, zero mandatory overhead being imposed
on code _not_ using some advanced feature).

I call the feature 'rarely used', but others may use it less
rarely.  Moshe Zadka, for example, has advocated that a
class-change is the right way to 'customize' a specific
instance, rather than adding a method to the instance itself
on the fly (I'm not quite sure why, and wouldn't want to
misrepresent his position, but I believe it has to do with a
wish to see behavior as associated with _classes_, not with
_instances_).


> But maybe more importantly, I don't know how to support this esoteric
> feature after the type/class unification is complete.  Under the new
> system, not all instances are born the same: instances may have slots
> for instance variables rather than a __dict__ -- using slots makes for
> more space-efficient instances.  (Having a __dict__ is still the
> default, and an instance can have both slots and a __dict__.)

So presumably not just ANY class-object may be assigned as
the __class__ attribute of a given instance: there will be a type
error if the class and the instance don't agree on slots/dictionary
use.  Can't this be checked at runtime when some
    instance.__class__ = anewclass
is attempted?  If this check slows down this specific esoteric
feature this shouldn't be a problem.  I'm not sure if the exact
needed constraint is _identity_ of slots in the original and new
class objects (I realize the slots are in the *instance* object,
but the _code_ to set or access them is in the class object,
right?) -- offhand it would seem so (if the slot assignment is
identical surely there should be no problems -- if the instance
has extra slots the new class would not know how to access
them, if the instance lacks some slots the class thinks are
there it should be even worse).  It seems to me it would be
better to keep the possibility of assigning __class__ even just
for old/new classes with identical slots/dictionary use, with
a TypeError (or some new specific subclass of it) in case of
any difference, rather than losing such assignment altogether.

Of course, such a change would still invalidate the specific
use of class assignment that I was making here, since the
'empty instance' I started with was of a class with no slots.
But, as you say, fortunately this specific idiom is being
replaced by a more direct new one:

> Fortunately, the type/class unification has a different idiom
> available to avoid __init_: __new__.  There are two parts to object
> construction, __new__ and __init__.  __new__ is a class method, and
> constructs a minimal object.  After __new__ has returned an
> instance,__init__ is called to further initialize the instance.  At
> least that's what the normal constructor (calling the class) does.
> You can call __new__ directly to construct an instance bypassing
> __init__.

An excellent alternative indeed!


Alex






More information about the Python-list mailing list