assignment to __class__ (was Re: Copy constructors)

Guido van Rossum guido at python.org
Mon Aug 13 09:37:06 EDT 2001


Glyph Lefkowitz <glyph at twistedmatrix.com> writes:

> Can you point me (and other readers just coming to this discussion) to a
> few URLs illuminating the key differences between 'new-style' and
> 'old-style' classes?  I'm going to do some reading up on the various PEPs,
> but if there are any posts on python-dev I can refer to...

The PEPs, the source code, and the unification tutorial at

    http://www.python.org/2.2/descrintro.html

> > In a sense, in 2.2 the new-style classes will still be experimental,
> > and it's quite likely that based upon feedback from users they will
> > change (for the better) in later versions.
> 
> Good to know.  I have to say that although I am among the biggest
> detractors to change, I can appreciate the difficulty of what you're
> doing; python is the first language I know of that has ever gone through
> significant *refactoring* (not whole-scale rewriting or just adding
> things) at both the implementation and design level.  I wish you good
> luck, and I hope that the voices from the "loyal opposition" are more of a
> help than a hindrance.
> 
> > Subclassing built-in types,
> 
> Operator overloading got me 90% of the way there, and that was really the
> only 90% I care about.  aside from isinstance() working on instances that
> are 'like' integers now, what have I gained?

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).

> > 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. :-)

> > class and static methods,
> 
> Those could be easily faked before, for the OO zealots; but I actually
> *like* the idea of using functions for things like that.  I prefer to
> organize my code at the module level, and I find the additional option of
> these method types just clutter.

Yet, they are amongst the most frequently requested features.

> > uniform introspection...
> 
> Aye, now there's the rub.  If we have uniform introspection, there's a
> certain expectation that features like this become _easier_ to use, not
> harder.  Introspection is a powerful feature, all the more powerful if
> it's uniform and systematic.

To me, introspection means being able to look at yourself, not
necessarily being able to modify yourself.  The new scheme definitely
makes discovery of features of objects easier -- you can *always* just
look at __class__.__dict__ etc.

> [ (snip) promise pattern is easy with class assignment ]
> 
> > If you know the type it's going to be eventually, you can use
> > C.__new__() to create an uninitialized C instance.
> 
> The point is that sometimes you don't...
> 
> Of course, you *could* create a class of which all your 'promised' objects
> are instances, and do specialization by having a reference in each
> instance to its 'real' class, but doesn't that seem a little silly given
> that we don't have to do it now? :-)

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?

> > You will still be able to modify *classes* dynamically -- although you
> > have to declare this option by putting __dynamic__ = 1 in your class
> > statement.
> 
> Hmm.  This seems like _less_ uniform introspection to me.  I do have to
> note that if this is a requirement, then a part of the Twisted coding
> standard will be to have all classes have __dynamic__ = 1; one rarely
> knows what code is going to have a bug _before_ the server is started :)

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.

> Also, as an aside: one of my favorite things about Python is the ability
> to fix bugs in a library you're using without having to modify the source
> to that library (if libmodule.version == '0.6.0': fix_libmodule_bug()).  
> 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
horrible things people used to do in DOS all the time (and to some
extent still do in Windows) that cause endless mysterious
incompatibilities between applications.

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.

> Could we have the default be the other way 'round?  (Has there already
> been a discussion of that?)

You bet.  See several of my previous posts.

> The obvious solution, if I understand python's internals correctly, is to
> make a type method slot, "tp_change_class".  Most types would just raise
> an exception; instances would continue to work the way they have been.  
> Aside from the fact that it's icky syntactically, is there anything that
> this would break or make unpleasant?

You don't need a new slot in the type method.

You just need to declare an object type whose descriptor for the
__class__ attribute is a get/set descriptor, where the set function
implements the proper restrictions.

> And if the syntax is not dealable, it would be a perfectly reasonable
> transition to have
> 
>  def change_class(obj, newclass):
>    obj.__class__ = newclass
> 
> be the current implementation of a function that would be implemented as a
> builtin in the future...

No need: you will be able to continue to use "obj.__class__ = newclass".

> Seriously, the dynamic nature of Python is what makes it cool.  I can
> understand removing meaningless dynamic features in order to make it
> faster (write access to locals() as a dictionary, for example) but I
> 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).

> I could imagine an effort to make Python less dynamic could well end up
> like the ill-fated project to make C more dynamic (C++).

The fact that you seem to believe this funny suggests that your
worldview is quite eccentric. :-)

> I want my Python code to execute faster, sure.  But before you start
> eliminating features for the sake of speed, ask yourself -- is anyone who
> is really concerned with efficiency writing code in *python*?  The speed
> freaks have long since moved over to ADA or C++ or some other similiarly
> torturous language to hate themselves at the speed of light while we're
> having fun slowly. :-)

Actually, speeding up Python is a very common request.  You probably
ignored those threads because *you* don't need it.  That is, until
more people use your code. :-)

> Allow me to be skeptical of the fact that there is such a thing as
> "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!

> 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!

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



More information about the Python-list mailing list