Play with classes

Discussion in 'Python' started by Zunbeltz Izaola, Feb 26, 2004.

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

    I hope it is clear enough :)

    Thanks in advance

    Zunbeltz
    Zunbeltz Izaola, Feb 26, 2004
    #1
    1. Advertising

  2. Zunbeltz Izaola

    Peter Otten Guest

    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.
    >
    > I hope it is clear enough :)
    >
    > Thanks in advance
    >
    > Zunbeltz


    How about assigning to __bases__?

    >>> class A:

    .... def alpha(self): print "alpha"
    ....
    >>> class B:

    .... def beta(self): print "beta"
    ....
    >>> class C: pass

    ....
    >>> C.__bases__

    ()
    >>> C.__bases__ = (A,B)
    >>> c = C()
    >>> c.alpha()

    alpha
    >>> c.beta()

    beta
    >>>


    Trying the same thing with newstyle class resulted in a TypeError:

    >>> E.__bases__ = (A, B)

    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    TypeError: __bases__ assignment: 'A' deallocator differs from 'object'

    Peter
    Peter Otten, Feb 26, 2004
    #2
    1. Advertising

  3. Zunbeltz Izaola <> writes:

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


    Is the following what you want ?

    ======================================================
    class TypeA: pass
    class TypeB: pass
    class TypeC: pass
    class SubtypeA: pass
    class SubtypeB: pass

    collect_bases = [(Mode, Type, Subtype)
    for Mode in [ModeA, ModeB]
    for Type in [TypeA, TypeB, TypeC]
    for Subtype in [SubtypeA, SubtypeB]]

    count = 0
    for bases in collect_bases:
    name = "UserClass%d" % count
    the_class = type(name, bases, {})
    globals()[name] = the_class
    count += 1
    ======================================================

    Now you can try

    >>> UserClass0.__bases__

    (<class '__main__.ModeA'>, <class '__main__.TypeA'>, <class
    '__main__.SubtypeA'>)

    >>> UserClass1.__bases__

    (<class '__main__.ModeA'>, <class '__main__.TypeA'>, <class
    '__main__.SubtypeB'>)
    >>> UserClass2.__bases__

    (<class '__main__.ModeA'>, <class '__main__.TypeB'>, <class
    '__main__.SubtypeA'>)

    And so on, until

    >>> UserClass11.__bases__

    (<class '__main__.ModeB'>, <class '__main__.TypeC'>, <class
    '__main__.SubtypeB'>)
    Jacek Generowicz, Feb 26, 2004
    #3
  4. Jacek Generowicz <> writes:

    > ======================================================
    > class TypeA: pass
    > class TypeB: pass
    > class TypeC: pass
    > class SubtypeA: pass
    > class SubtypeB: pass
    >
    > collect_bases = [(Mode, Type, Subtype)
    > for Mode in [ModeA, ModeB]
    > for Type in [TypeA, TypeB, TypeC]
    > for Subtype in [SubtypeA, SubtypeB]]
    >
    > count = 0
    > for bases in collect_bases:
    > name = "UserClass%d" % count
    > the_class = type(name, bases, {})
    > globals()[name] = the_class
    > count += 1
    > ======================================================


    Oooops, the first 4 lines got lost:

    ======================================================
    __metaclass__ = type

    class ModeA: pass
    class ModeB: pass
    class TypeA: pass
    class TypeB: pass
    class TypeC: pass
    class SubtypeA: pass
    class SubtypeB: pass

    collect_bases = [(Mode, Type, Subtype)
    for Mode in [ModeA, ModeB]
    for Type in [TypeA, TypeB, TypeC]
    for Subtype in [SubtypeA, SubtypeB]]

    count = 0
    for bases in collect_bases:
    name = "UserClass%d" % count
    globals()[name] = type(name, bases, {})
    count += 1
    ======================================================
    Jacek Generowicz, Feb 26, 2004
    #4
  5. Jacek Generowicz <> writes:

    Thank for the help.
    >
    > Oooops, the first 4 lines got lost:
    >
    > ======================================================
    > __metaclass__ = type
    >


    I am not an expert and i don't understand very well things like
    __metaclass__, but it not redundat this line? From the Language Reference

    """
    __metaclass__
    This variable can be any callable accepting arguments for name, bases,
    and dict. Upon class creation, the callable is used instead of the
    built-in type(). New in version 2.2.
    """

    so I think __metaclass__ = type is the same as not defining __metaclass__

    Regards,

    Zunbeltz

    > class ModeA: pass
    > class ModeB: pass
    > class TypeA: pass
    > class TypeB: pass
    > class TypeC: pass
    > class SubtypeA: pass
    > class SubtypeB: pass
    >
    > collect_bases = [(Mode, Type, Subtype)
    > for Mode in [ModeA, ModeB]
    > for Type in [TypeA, TypeB, TypeC]
    > for Subtype in [SubtypeA, SubtypeB]]
    >
    > count = 0
    > for bases in collect_bases:
    > name = "UserClass%d" % count
    > globals()[name] = type(name, bases, {})
    > count += 1
    > ======================================================
    Zunbeltz Izaola, Feb 26, 2004
    #5
  6. Zunbeltz Izaola

    Terry Reedy Guest

    "Zunbeltz Izaola" <> wrote in message
    news:...
    > 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 class statement, like all statements except the global directive, it a
    runtime executable statement. So, in a sense, all class objects are
    defined (created) at runtime. So you are perhaps asking, "Can I write a
    class statement at runtime (using user input)?" If so, yes. Create a
    string with the code you want executed, then exec it with an exec
    statement. Or you can use the approach others suggested of interpreting
    user input to build up a class object. Your choice.

    Terry J. Reedy
    Terry Reedy, Feb 26, 2004
    #6
  7. 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.
    >
    >

    ....
    Mike C. Fletcher, Feb 26, 2004
    #7
  8. Peter Otten <> wrote in message news:<c1kmj0$28f$04$-online.com>...
    > Trying the same thing with newstyle class resulted in a TypeError:
    >
    > >>> E.__bases__ = (A, B)

    > Traceback (most recent call last):
    > File "<stdin>", line 1, in ?
    > TypeError: __bases__ assignment: 'A' deallocator differs from 'object'
    >


    You can't do that with new style classes! I guess because of some
    subtle issue with metaclasses, but I don't really know.

    The OP needs "type", the custom metaclass:

    UserClass=type("UserClass",(ModeA, TypeB, SubtypeB),{})


    Michele Simionato
    Michele Simionato, Feb 26, 2004
    #8
  9. In article <>, Zunbeltz Izaola wrote:

    > Supose the user whant to combine ModeA with TypeB and SubtypeB, so I need
    > something like
    >
    > class UserClass(ModeA, TypeB, SubtypeB):



    You can use the type builtin (2.2 and above) to create a class type
    dynamically. Syntax is

    type(name_string, bases_tuple, methods_dict)

    For example:

    In [68]: foo = type('Foo', (object,), {})
    In [69]: foo.mro()
    Out[69]: [<class '__main__.Foo'>, <type 'object'>]

    Dave Cook
    David M. Cook, Feb 26, 2004
    #9
  10. Zunbeltz Izaola <> writes:

    > Jacek Generowicz <> writes:
    >
    > Thank for the help.


    I hope that it is what you were asking for.

    Of course, my posting such a solution should in no way be interpreted
    as a suggestion that it is appropriate to your _real_ problem. You may
    well want a completely different approach, but I can't tell without
    knowing more about your application.

    > > __metaclass__ = type

    >
    > I am not an expert and i don't understand very well things like
    > __metaclass__, but it not redundat this line? From the Language Reference
    >
    > """
    > __metaclass__
    > This variable can be any callable accepting arguments for name, bases,
    > and dict. Upon class creation, the callable is used instead of the
    > built-in type(). New in version 2.2.
    > """
    >
    > so I think __metaclass__ = type is the same as not defining __metaclass__


    It is indeed tempting to conclude that from what you have quoted.

    One of the beauties of Python is its highly interactive nature, and
    the ease with which you can try things out. Your hypothesis that
    "__metaclass__ = type is the same as not defining __metaclass__" can
    be refuted by the Python interpreter itself within about 10 seconds of
    work. Take the code I sent, remove the binding of __metaclass__ and
    run the code. You will find that Python replies:

    TypeError: a new-style class can't have only classic bases

    As written in my example, ("class ModeA: pass" etc.) all the classes
    are classic, because they do not inherit from object.

    >>> class classic: pass

    ....
    >>> class newstyle(object): pass

    ....
    >>> type(classic)

    <type 'class'>
    >>> type(newstyle)

    <type 'type'>

    I want them to be new-style classes, because I am going to create new
    classes which inherit from them, using type. This means of creating
    classes creates new-style classes, and new style classes, as the error
    message above suggests, "can't have only classic bases".

    So, I could either make ModeA & co inherit from object, or I could
    make all classes new-style ones by default, by binding __metaclass__
    to type.

    Alternatively, I could not use type to create the UserClasses, but
    types.ClassType (types is a module). Alternatively I could use use
    type(ModeA) which would pick the appropriate metaclass for creation of
    your UserClasses depending on the situation.

    > """
    > __metaclass__
    > This variable can be any callable accepting arguments for name, bases,
    > and dict. Upon class creation, the callable is used instead of the
    > built-in type(). New in version 2.2.
    > """


    Hmm. Is that a documentation bug? I suspect that it should read "
    .... instead of types.ClassType"


    [ So, here's a classic class version of the original:

    class ModeA: pass
    class ModeB: pass
    class TypeA: pass
    class TypeB: pass
    class TypeC: pass
    class SubtypeA: pass
    class SubtypeB: pass

    collect_bases = [(Mode, Type, Subtype)
    for Mode in [ModeA, ModeB]
    for Type in [TypeA, TypeB, TypeC]
    for Subtype in [SubtypeA, SubtypeB]]

    count = 0
    for bases in collect_bases:
    name = "UserClass%d" % count
    globals()[name] = type(ModeA)(name, bases, {})
    # or you could "import types" and do the following
    # globals()[name] = types.ClassType(name, bases, {})
    count += 1

    ]
    Jacek Generowicz, Feb 27, 2004
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. David

    Classes within classes

    David, Jul 21, 2005, in forum: ASP .Net
    Replies:
    2
    Views:
    4,939
    David
    Jul 22, 2005
  2. lonelyplanet999
    Replies:
    1
    Views:
    2,210
    VisionSet
    Nov 13, 2003
  3. Carfield Yim
    Replies:
    1
    Views:
    1,415
    Andrew Thompson
    May 31, 2004
  4. Holger Joukl
    Replies:
    0
    Views:
    283
    Holger Joukl
    Feb 26, 2004
  5. Paul Rubin
    Replies:
    1
    Views:
    282
    Skip Montanaro
    May 14, 2005
Loading...

Share This Page