Using metaclassed to dynamically generate a class based on a parameter to the objects init function.

Discussion in 'Python' started by sashang@gmail.com, Jun 23, 2006.

  1. Guest

    Hi

    I'd like to use metaclasses to dynamically generate a class based on a
    parameter to the objects init function.

    For example:

    class MetaThing(type):
    def __init__(cls, name, bases, dict, extra_information):
    super(MetaThing, cls).__init__(name, bases, dict)
    #setup the class based on the parameter extra_information

    class Thing:
    __metaclass__ = MetaThing
    def __init__(self, extra_information):
    #Somehow pass extra_information to the MetaThing

    extra_information = 1
    t = Thing(extra_information)

    The above sample won't work but I hope it demonstrates what I'm trying
    to do.
     
    , Jun 23, 2006
    #1
    1. Advertising

  2. Re: Using metaclassed to dynamically generate a class based on aparameter to the objects init function.

    wrote:
    > Hi
    >
    > I'd like to use metaclasses to dynamically generate a class based on a
    > parameter to the objects init function.


    Do you really need a metaclass for this ?

    > For example:
    >
    > class MetaThing(type):
    > def __init__(cls, name, bases, dict, extra_information):
    > super(MetaThing, cls).__init__(name, bases, dict)
    > #setup the class based on the parameter extra_information
    >
    > class Thing:
    > __metaclass__ = MetaThing
    > def __init__(self, extra_information):
    > #Somehow pass extra_information to the MetaThing
    >
    > extra_information = 1
    > t = Thing(extra_information)


    Why would you want a new *class* here ?

    > The above sample won't work but I hope it demonstrates what I'm trying
    > to do.


    Not enough, I'm afraid - unless it's just me being dumb. From what I see
    here, you just can add the extra informations on the object in the
    initializer. What's your *real* use case ?




    --
    bruno desthuilliers
    python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
    p in ''.split('@')])"
     
    Bruno Desthuilliers, Jun 23, 2006
    #2
    1. Advertising

  3. Guest

    Bruno Desthuilliers wrote:
    > wrote:
    > > Hi
    > >
    > > I'd like to use metaclasses to dynamically generate a class based on a
    > > parameter to the objects init function.

    >
    > Do you really need a metaclass for this ?
    >
    > > For example:
    > >
    > > class MetaThing(type):
    > > def __init__(cls, name, bases, dict, extra_information):
    > > super(MetaThing, cls).__init__(name, bases, dict)
    > > #setup the class based on the parameter extra_information
    > >
    > > class Thing:
    > > __metaclass__ = MetaThing
    > > def __init__(self, extra_information):
    > > #Somehow pass extra_information to the MetaThing
    > >
    > > extra_information = 1
    > > t = Thing(extra_information)

    >
    > Why would you want a new *class* here ?
    >
    > > The above sample won't work but I hope it demonstrates what I'm trying
    > > to do.

    >
    > Not enough, I'm afraid - unless it's just me being dumb. From what I see
    > here, you just can add the extra informations on the object in the
    > initializer. What's your *real* use case ?
    >
    >


    The extra_information is used in MetaThing to tell it what attributes
    to add to the class. For example:

    class MetaThing(type):
    def __init__(cls, name, bases, dict, extra_information):
    super(MetaThing, cls).__init__(name, bases, dict)
    #setup the class based on the parameter extra_information
    setattr(cls, make_name(extra_information),
    make_object(extra_information))

    Does that clarify things? I might have the wrong approach - I'm new to
    metaclasses. However I do think the solution to my problem lies with
    them since I have to dynamically generate a class and metaclasses
    provide a mechanism for doing this.
     
    , Jun 23, 2006
    #3
  4. wrote:
    > However I do think the solution to my problem lies with
    > them since I have to dynamically generate a class and metaclasses
    > provide a mechanism for doing this.


    You rarely need a custom metaclass to generate classes. A class factory

    def makeclass(classname, *attributes):
    cls = type(classname, mybases, mydic)
    for name, value in attributes:
    setattr(cls, name, attr)
    return cls

    is the typical solution for your use case.

    OTOH, if you are looking for use classes for metaclasses, look at the
    Python Wiki
    and use Google.

    Michele Simionato
     
    Michele Simionato, Jun 23, 2006
    #4
  5. Re: Using metaclassed to dynamically generate a class based on aparameter to the objects init function.

    wrote:
    > Bruno Desthuilliers wrote:
    >
    >> wrote:
    >>
    >>>Hi
    >>>
    >>>I'd like to use metaclasses to dynamically generate a class based on a
    >>>parameter to the objects init function.

    >>
    >>Do you really need a metaclass for this ?
    >>
    >>
    >>>For example:
    >>>
    >>>class MetaThing(type):
    >>> def __init__(cls, name, bases, dict, extra_information):
    >>> super(MetaThing, cls).__init__(name, bases, dict)
    >>> #setup the class based on the parameter extra_information
    >>>
    >>>class Thing:
    >>> __metaclass__ = MetaThing
    >>> def __init__(self, extra_information):
    >>> #Somehow pass extra_information to the MetaThing
    >>>
    >>>extra_information = 1
    >>>t = Thing(extra_information)

    >>
    >>Why would you want a new *class* here ?
    >>
    >>
    >>>The above sample won't work but I hope it demonstrates what I'm trying
    >>>to do.

    >>
    >>Not enough, I'm afraid - unless it's just me being dumb. From what I see
    >>here, you just can add the extra informations on the object in the
    >>initializer. What's your *real* use case ?
    >>

    >
    > The extra_information is used in MetaThing to tell it what attributes
    > to add to the class. For example:
    >
    > class MetaThing(type):
    > def __init__(cls, name, bases, dict, extra_information):
    > super(MetaThing, cls).__init__(name, bases, dict)
    > #setup the class based on the parameter extra_information
    > setattr(cls, make_name(extra_information),
    > make_object(extra_information))
    >
    > Does that clarify things? I might have the wrong approach


    There's at least something wrong here : the metaclass code is executed
    when the class statement (the one for a class having this metaclass) is
    eval'd. It won't be called on class instanciation.

    http://www.python.org/download/releases/2.2.3/descrintro/#__new__

    Also, you need to understand that modifying a class with impact all it's
    instances.

    > - I'm new to
    > metaclasses. However I do think the solution to my problem lies with
    > them since I have to dynamically generate a class


    You don't have to create classes for this - it's perfectly legal to set
    attributes (data or methods) on a per-object basis. Classes are more
    object-factories than rigid types. Just add the needed extra attributes
    in the __init__ (the class one, not the metaclass) and you should be done.

    > and metaclasses
    > provide a mechanism for doing this.


    Metaclasses provides a hook on class creation process. But AFAICT, you
    don't necessarily need metaclasses to dynamically create classes...




    --
    bruno desthuilliers
    python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
    p in ''.split('@')])"
     
    Bruno Desthuilliers, Jun 23, 2006
    #5
  6. Carl Banks Guest

    wrote:
    > Hi
    >
    > I'd like to use metaclasses to dynamically generate a class based on a
    > parameter to the objects init function.
    >
    > For example:
    >
    > class MetaThing(type):
    > def __init__(cls, name, bases, dict, extra_information):
    > super(MetaThing, cls).__init__(name, bases, dict)
    > #setup the class based on the parameter extra_information
    >
    > class Thing:
    > __metaclass__ = MetaThing
    > def __init__(self, extra_information):
    > #Somehow pass extra_information to the MetaThing
    >
    > extra_information = 1
    > t = Thing(extra_information)


    Tricky. First of all, __init__ belongs to the class, not the object.
    (Sometimes it's convenient to say it's the object's __init__ method,
    but when mucking around with metaclasses it's important be precise
    about what belongs to who, otherwise everyone gets confused.) Because
    __init__ belongs to the class, the object's class must already exist
    before calling it, which is contrary to what you seem to want to do.

    It seem as if, when creating an object, you want to create it's very
    own class to go with it. I suppose there could be use case for it, but
    I highly recommend you consider whether features like instance methods
    or classmethods can accomplish what you want. If you'd still rather
    that a Thing have its very own class, I recommend you forget about
    metaclasses and use a factory function with a closure:

    def create_thing(extra_information):
    class Thing(object):
    def __init__(self):
    # use extra_information here
    ...
    return Thing()

    If you don't like this, or if you insist on using a metaclass, and you
    don't care that you'll be confusing the hell out of anyone reading the
    code, the answer is to override the class's __new__ method. Unlike
    __int__, the __new__ method can return any object it wants, including
    an object of a different class. The class should subclass itself in
    its __new__ method, providing the passed extra_information to the
    constructor of the new subclass, then return an object created from
    that subclass. The subclass should override __new__ so as not to
    repeat the hijinks of the class's __new__.

    Don't follow? The actual source code won't be much easier. Here's an
    example.

    class MetaThing(type):
    def __new__(metacls,name,bases,clsdict,extra_information):
    # use extra_information
    return type.__new__(metacls,name,bases,clsdict)

    class Thing(object):
    def __new__(cls,extra_information):
    clsdict = {'__new__':eek:bject.__new__}
    my_very_own_class = MetaThing(
    "Subthing",(Thing,),clsdict,extra_information)
    return object.__new__(my_very_own_class)

    Note that Thing doesn't and shouldn't define __metaclass__, since it
    creates its subclass directly from the metaclass's constructor. You
    could, of course, also use the closure method I demonstrated above in
    Thing's __new__ method--essentially you'd be using Thing's __new__
    method as the factory function.


    > The above sample won't work but I hope it demonstrates what I'm trying
    > to do.


    Again, I highly recommend you consider whether what you're "trying to
    do" can be done more easily with instance or class methods.


    Carl Banks
     
    Carl Banks, Jun 23, 2006
    #6
  7. Carl Banks Guest

    wrote:
    > The extra_information is used in MetaThing to tell it what attributes
    > to add to the class. For example:
    >
    > class MetaThing(type):
    > def __init__(cls, name, bases, dict, extra_information):
    > super(MetaThing, cls).__init__(name, bases, dict)
    > #setup the class based on the parameter extra_information
    > setattr(cls, make_name(extra_information),
    > make_object(extra_information))
    >
    > Does that clarify things?


    Why do the extra attributes need to be part of the class? ISTM each
    instance has its own class; therefore there it doesn't matter whether a
    member is a class member or an instance member.


    Carl Banks
     
    Carl Banks, Jun 23, 2006
    #7
  8. Carl Banks <> wrote:

    > wrote:
    > > The extra_information is used in MetaThing to tell it what attributes
    > > to add to the class. For example:
    > >
    > > class MetaThing(type):
    > > def __init__(cls, name, bases, dict, extra_information):
    > > super(MetaThing, cls).__init__(name, bases, dict)
    > > #setup the class based on the parameter extra_information
    > > setattr(cls, make_name(extra_information),
    > > make_object(extra_information))
    > >
    > > Does that clarify things?

    >
    > Why do the extra attributes need to be part of the class? ISTM each
    > instance has its own class; therefore there it doesn't matter whether a
    > member is a class member or an instance member.


    It matters for a "member" that is actually a special-method: Python's
    automatic search for special methods (except on old-style classes) does
    NOT look at per-instance members, only at per-class ones.

    But, as many have already said, a custom metaclass is probably not the
    optimal tool for this task (and it's definitely wrong to alter a
    metaclass's __init__'s signature in incompatible ways -- you would never
    be able to make classes with metaclass MetaThing with a normal class
    statement, since the intrinsic call to the metaclass's __init__ fails!).


    Alex
     
    Alex Martelli, Jun 23, 2006
    #8
  9. Re: Using metaclassed to dynamically generate a class based on aparameter to the objects init function.

    Le Vendredi 23 Juin 2006 16:03, Carl Banks a écrit :
    > Don't follow?  The actual source code won't be much easier.  Here's an
    > example.
    >
    >     class MetaThing(type):
    >         def __new__(metacls,name,bases,clsdict,extra_information):
    >             # use extra_information
    >             return type.__new__(metacls,name,bases,clsdict)
    >
    >     class Thing(object):
    >          def __new__(cls,extra_information):
    >              clsdict = {'__new__':eek:bject.__new__}
    >              my_very_own_class = MetaThing(
    >                  "Subthing",(Thing,),clsdict,extra_information)
    >              return object.__new__(my_very_own_class)


    Hmmm, rigourously speaking, metaclasses in OOP are classes whose instances are
    class.
    Something like that :

    In [114]: class MetaClass(object) :
    .....: def __new__(cls, name, bases=(), **some_attributes) :
    .....: return type('newtype %s' % name, bases, some_attributes)
    .....:
    .....:


    Let's play with it :


    In [115]: Concrete1 = MetaClass('conc1', (), classprop=1, method=lambda
    s : "fun")

    In [116]: Concrete2 = MetaClass('conc1', (), classprop=1, method=lambda
    s : "fun")

    In [117]: isinstance(Concrete1(), Concrete2)
    Out[117]: False

    In [118]: isinstance(Concrete1(), Concrete1)
    Out[118]: True

    In [119]: Concrete1().method()
    Out[119]: 'fun'

    In [120]: Concrete1.classprop
    Out[120]: 1

    In [121]: class Abstract(object) :
    .....: def __init__(self) : self._attr = self._attr_type()
    .....:
    .....:

    In [122]: Concrete = MetaClass('concrete_with_list', (Abstract,),
    _attr_type=list)

    In [123]: Concrete()._attr
    Out[123]: []

    In [124]: Concrete = MetaClass('concrete_with_int', (Abstract,),
    _attr_type=int)

    In [125]: Concrete()._attr
    Out[125]: 0

    In [126]: type(Concrete)
    Out[126]: <type 'type'>

    In [127]: type(Concrete())
    Out[127]: <class '__main__.newtype concrete_with_int'>


    regards,



    --
    _____________

    Maric Michaud
    _____________

    Aristote - www.aristote.info
    3 place des tapis
    69004 Lyon
    Tel: +33 426 880 097
     
    Maric Michaud, Jun 23, 2006
    #9
  10. Re: Using metaclassed to dynamically generate a class based on aparameter to the objects init function.

    Le Vendredi 23 Juin 2006 17:09, Maric Michaud a écrit :
    > Hmmm, rigourously speaking, metaclasses in OOP are classes whose instances
    > are class.

    Ooops, sorry i didn't notice you were calling type's __new__ (and not
    object'sone).


    --
    _____________

    Maric Michaud
    _____________

    Aristote - www.aristote.info
    3 place des tapis
    69004 Lyon
    Tel: +33 426 880 097
     
    Maric Michaud, Jun 23, 2006
    #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. Tony Cheng
    Replies:
    1
    Views:
    8,218
    Juan T. Llibre
    Feb 24, 2006
  2. Replies:
    1
    Views:
    664
    Jules
    Aug 18, 2005
  3. 7stud
    Replies:
    11
    Views:
    700
    Dennis Lee Bieber
    Mar 20, 2007
  4. Jess
    Replies:
    4
    Views:
    445
  5. news.aon.at
    Replies:
    11
    Views:
    651
    Ian Collins
    Jan 29, 2011
Loading...

Share This Page