assignment to __class__ (was Re: Copy constructors)

Alex Martelli aleaxit at yahoo.com
Mon Aug 13 16:25:45 EDT 2001


"Guido van Rossum" <guido at python.org> wrote in message
news:cpzo94dqvy.fsf at cj20424-a.reston1.va.home.com...
    ...
>     http://www.python.org/2.2/descrintro.html

I thought I had understood it, but still don't see where it mentions
"x.__class__ = whatever" now being forbidden or restricted?


> You can subclass dictionary, and the resulting object will be
> acceptable as a dictionary where the runtime requires a "real"
> dictionary.  Ditto for e.g. files (once I make them subclassable).

This is huge (for dictionaries, definitely -- I've never yet run
into a place where the runtime smacked me because it typechecked
for a "real" file, but I can see it would be just as important).


> > > get/set methods,
> >
> > I already *have* get/set methods, in 1.5.2; see
> > twisted.python.reflect.Accessor :-)
>
> Now everybody else gets them without having to buy into your twisted
> philosophy. :-)

This is also important, for a peculiar reason -- having built-in ways
to do "the right thing" even though it wasn't all that hard to do it
before.  The peculiar reason is: in a multi-person project, when the
Language blesses some idiom (such as implicit getter/setter, aka
"the property idiom", versus explicit getFoo()/setFoo() calls), it
becomes that much easier to get group consensus that, yes, this
idiom IS the right thing to adopt as the style for a certain library
or framework.


> To me, introspection means being able to look at yourself, not
> necessarily being able to modify yourself.  The new scheme definitely

My extant English dictionaries support your interpretation
of this word.


> It would be relatively easy to allow __class__ assignment only if (a)
> the new class is a subclass of the old class, and (b) the size of the
> new instance is the same as the old instance.  Would this be sufficient?

Does 'size' in this context mean 'number of slots'?  In this case, albeit
with somewhat peculiar contortions (requiring new.classobj or the
equivalent), I think it would be sufficient for all cases that come to
my mind -- I'd just have to put any extra attributes in the __dict__
(which I do today for *every* attribute anyway:-).

The "generate empty object through __class__ assignment" trick
would also become sort-of-possible again (although of no practical
interest whatsoever:-) -- to wit:

def make_empty_copy(any_object):
    klass = any_object.__class__
    class Empty(klass):
        def __init__(self, *args, **kwds): pass
    newcopy = Empty()
    class Full(Empty):
        __init__ = klass.__init__
        __name__ = klass.__name__
    newcopy.__class__ = Full
    return newcopy

the Full class is not really the same as any_object.__class__, but
nobody's gonna find out (presumably) since it's undistinguishable
under normal use of isinstance or any behavior-test whatsoever
(or have I forgotten to copy some needed attribute for that?).

These classes Empty and Full are examples of what I mean above
as roughly 'equivalent' to new.classobj calls:-).  I think I could
handle 'real' cases of class-change (worst case) through similar
means, i.e. generating on the fly a class that's basically what I
need but formally inherits from the object's original class so it
can be assigned.  I realize this will not support _deleting_ any
method wrt the original class, but that's not a need in any case
that easily comes to mind.


> Assuming you have a few base classes from which everything else
> builds, you only need to add __dynamic__ = 1 to those base classes.
> You can also write a metaclass (inheriting from type) that changes the
> default for __dynamic__ to 1, but it's probably easier to just seed
> your base classes.

Good point.  Yes, specifying that every class that participates in the
Super Duper Framework must directly or indirectly extend SupDupObj,
while not _quite_ as handy as not even having to specify it, seems
basically OK and pretty typical of many framework.  I may cringe a
bit seeing Python gradually moving away from the utter simplicity
of signature-based polymorphism, but that's more of an instinctive
reaction than a reasoned one based on actual use-cases.


> > This greatly eases deployment.  Fixing bugs in a running server is also
> > pretty important if you don't have the option to take the server down...
>
> Hm, I happen to hate it when people do this, because it's so fragile:
> there are lots of things that could break.  It reminds me of the

Yes, but, when servers DO have to stay up, fixing them on the fly,
albeit indeed fragile, is a specified constraint.  I guess in some cases
one could devise alternate strategies: putting up a new fixed server
process on a different machine, port-redirecting all new requests to
the new machine, and finally pulling down the old buggy server when
the conversations for the requests it was serving at fix-time are gone.

But that constrains your deployment possibilities enormously, and it
has its own huge fragilities (e.g., the server must be architected so
that multiple instances, old and new, can update the same database
without tripping on each other's feet -- just for starters).

> Really, I understand you're in love with this stuff, but I feel it as
> my responsibility to protect typical Python users from burning
> themselves.  That's why I want to require explicit declaration of
> certain forms of dynamicism.

*blink* I had never thought Python's philosophy was protecting
"typical users" from themselves -- I thought that was the idea
of Pascal, Modula-2, &c, to Eiffel, the languages that know what's
good for you better than you know yourself, so they'll force you
to program the way Wirth (or Meyer) KNOWS is the one right
way to program.  As I previously read your recent posts, I thought
that the __dynamic__ thing was about performance instead...?


> > suspect that many more dynamic features than you like are really really
> > useful.
>
> In the hands of a select few, yes.  For most people, the dynamicism is
> just more rope to hang themselves (just as the fact that variable
> references aren't checked until you use them).

Can we expect variable declarations a few minor releases from
now, then?  That would presumably be consistent with the new
focus on protecting typical users from themselves.


> > "typical" code :).  Most 'typical' python code could probably be written
> > in Java without much difference except a little more typing.
>
> Exactly.  But people still choose Python because there's less typing!

In two senses of the word 'typing', too -- both the one that's about
keyboards, and the one that's about declaring variable's types:-).


> > It's when you get to the boundary conditions -- adding attributes
> > dynamically, reflection, reloading, deploying, porting -- that's
> > where Python starts to shine.
>
> And all I'm trying to do is to make those things safer.  A chainsaw is
> a great tool -- and also very dangerous.  Should we forbid the use of
> chainsaws?  Of course not.  Should we try to make them safer by adding
> protective devices?  Of course we should!

"Of course" as long as the extra devices don't significantly interfere
with the tools' previous strengths in terms of cost and power.  When
the significant interference is there, there is no "of course" about it --
it becomes a highly problematical trade-off.


Alex






More information about the Python-list mailing list