Play with classes
Mike C. Fletcher
mcfletch at rogers.com
Thu Feb 26 12:01:36 EST 2004
As another poster noted, all classes are created at run-time. There's
even a hook that let's you intercept the creation of a class called the
"metaclass hook", however, to deal with the question directly before I
go off on a tangent...
There are two major approaches you can take to elegantly composing
classes at run-time; Factory functions and metaclasses. Here's an
example of the factory function approach, (which is probably most
appropriate in your case (user is only creating new classes via GUI
interactions, no need for ability to sub-class in Python code, no need
for addition of newly-created methods/functions, i.e. straight
composition)):
def createClass( name, baseClasses, dictionary ):
"""Create a new class object and return it"""
# reshuffle baseClasses here
# manipulate dictionary here
# check that name is unique here
# register with some global registry here
# register pickle helpers here
if definitions.has_key( uniqueFingerprint):
return that
else:
# if you were paying attention, you'll notice
# that save for the manipulation comments we
# just call this...
return type( name, baseClasses, dictionary )
If, however, your users may *also* want to define these classes as part
of Python modules (for an extension mechanism), you may want to subclass
"type" to encode your registration/reshuffling/manipulation/etc.
directly and then use that metaclass (sub-class of type) for each of
your classes:
class MetaFoo( type ):
"""Metaclass for the example code"""
definitions = {}
def __new__( metacls, name, bases, dictionary ):
# reshuffle baseClasses here
# manipulate dictionary here
# check that name is unique here
uniqueFingerprint = name, bases
if metacls.definitions.has_key( uniqueFingerprint ):
# Note: this likely *isn't* a good idea, as it can really
# surprise your users to discover that their classes
# are silently unified with another class! Just a demo...
return metacls.definitions.get( uniqueFingerprint )
else:
result = super(MetaFoo,metacls).__new__(
metacls, name, bases, dictionary
)
metacls.definitions[ uniqueFingerprint ] = result
# register with some global registry here
# register pickle helpers here
return result
__metaclass__ = MetaFoo
class ModeA:
pass
class ModeB:
pass
class ModeC( ModeA, ModeB ):
pass
class ModeD( ModeA, ModeB ):
pass
print MetaFoo( 'A', (), {} ) is MetaFoo( 'A', (), {} )
As noted in the comments above, likely you don't even want the effect of
having the class-cache (too confusing for users, mostly, but I wanted
some sort of manipulation to stick in to say "something happens here" :)
), so there's no particular value to the metaclass version for your
case. I just wanted an opportunity to work on an example for my talk...
I'm sick, I know...
Some things to keep in mind:
* Your new class instances will *not* be pickle-able (using either
method) unless they are registered explicitly somewhere in an
importable module. You will need to figure out how to ensure
that, on unpickling, your newly-created classes are available
(e.g. by storing their definitions in a database somewhere and
hooking import to treat the DB as a module).
* metaclasses are more fun :) , but they take some getting used to,
and are probably overkill for this simple excursion into
metaprogramming
* The "new" module has an (ironically) older API for creating class
objects
Have fun,
Mike
Zunbeltz Izaola wrote:
>Hi to all!
>
>I wonder if it possible (i'm sure python can do :-) ) to define classes on
>runtime. My problem (schematically) is the folowwin.
>
>The User can choise betwenn 3 property of an object.
>
>Mode, Type and Subtype.
>
>I have the following classes defined
>
>ModeA, ModeB, TypeA, TypeB, TypeC, SubtypeA, SubtypeB.
>
>Supose the user whant to combine ModeA with TypeB and SubtypeB, so I need
>something like
>
>class UserClass(ModeA, TypeB, SubtypeB):
> pass
>
>I can define all the posibilitys different classes and the using nested
>if/else I can use the correct class, but I want to know if there is a way
>generate in the fly and in this way there is no necesarity to change code whe
>new Modes or Types are created.
>
>
...
More information about the Python-list
mailing list