Re-executing the code object from a class 'declaration'

Alex Martelli aleaxit at yahoo.com
Wed Oct 6 21:18:40 CEST 2004


Carlos Ribeiro <carribeiro at gmail.com> wrote:
   ...
> > Personally, I _like_ using 'class' statements to make classes and 'def'
> > statements to make functions; I don't see either as hacks.  Messing with
   ...
> I'm not sure if I understood what you meant. My common sense tells me
> that the class-inside-a-def is more acceptable, given all the black
> magic that we had to go through to be able to re-execute the class

Yep, sounds about right.

> statement. But the function above really returns a class... which is
> 'wrong', but many counts (although nothing stops it from happening,

Ah, that's our disagreement, I guess.  I consider Factory a perfectly
sensible and respectable design pattern, and thus I see nothing wrong a
function making and returning a new object (class or otherwise).

> after all, classes are objects pretty much like any other object,
> albeit with the special ability to build new objects instances).

Any callable can build whatever kind of objects it wants -- class
objects have no "special ability" in this regard.  Where class objects
are unique is in the automatic chain of delegation -- instance to class
to bases -- when an attribute is being looked up.


> On the other hand, the re-execute-class-statement trick is a real hack
> -- specially when seen from the inside. However, if everything is
> clearly hidden in a metaclass (and I mean, a *real* metaclass, not a
> def __metaclass__()); better yet, if the metaclass itself is hidden in
> a base class; what do you think is cleaner?

I think that, when feasible, making classes by executing a class
statement (and functions by executing a def statement) is cleanest.
If you can get substantial added value using type(....) calls or
new.function(...) calls or whatever, so be it, of course -- if you NEED
to get to that level, so be it, there's nothing sinful or bad about it,
it may just be a tad harder to understand and maintain... no big deal,
not comparable to (e.g.) building up a string and then doing 'exec' on
it (THAT _is_ sinful and bad and maybe will make Guido cry...;-).


> a) class-inside-a-def
> 
> def BuildTemplate(<template parameters>)
>     class TemplateClass(...):
>         ...
>     return TemplateClass
> T = BuildTemplate(<params>)

Quite clean, IMHO, if it does all you need.


> b) re-exec-class
> 
> # GenericTemplate is a metaclass-enabled ancestor
> from template import GenericTemplate
> class TemplateClass(GenericTemplate):
>         ...
> 
> T = TemplateClass.NewTemplate(<params>)

To be honest I never really understood why you liked that one so much,
apart from the fascinating possibilities it offers for delving into
normally ignored details of 'class' statements' execution;-)

Seriously: classes have one incredible syntax advantage when you expose
them to users... users who write class statements get to write any gd
code they like in a context where every localname created ends up in a
dict, then your metaclass gets to process the dict, etc, etc.  In
comparison, functions are fine, with keyword parameters, for the
equivalent of assignment statements, i.e.,

class foo(subletWayToGetMetaclassOmega):
    bar = 23

and

foo = factoryFunctionOmega(bar=23)

are roughly equivalent; but as soon as the body of 'class foo' starts
having def statements, class statements, loops, etc, the factory
function has a hard time keeping up.  This syntax advantage has little
to do with the *intended* semantics of 'class' vs function calls, and is
the root of most "metaclass abuse" I've seen (and perpetrated -- though
not in production code...).

But it doesn't seem to be what you're after, and a couple days ago I saw
somebody else asking about a metaclass to be called directly (where a
class statement _was_ clearly what they needed, IMHO), so there must be
something more going on here... I think I'll nickname it "class
struggle"... many people DO seem to be struggling with classes, these
days...


> c) neither of the above -- there must be a better way to do it.

...must there...?  Maybe I'm being short-sighted (wouldn't be the first
time), but I can't see.  If you could have your heart's desire, within
the general framework of Python, how WOULD you code what you're after
(which I'm still not entirely clear about)?  I mean, how would it look
to the user -- how it looks like _inside_ is a relatively minor issue...


Alex



More information about the Python-list mailing list