Play with classes

Mike C. Fletcher mcfletch at rogers.com
Thu Feb 26 18:01:36 CET 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