Automatic Attribute Assignment during Class Inheritance

Discussion in 'Python' started by gizli, Sep 10, 2009.

  1. gizli

    gizli Guest

    Hi all,

    I have been trying to do a programming trick with python and so far I
    failed. I am using sqlalchemy in my code and writing a framework with
    it. This framework uses something called polymorphic identity
    attribute to define the do single table inheritance. Here's roughly
    how it works:

    1. Define a base ORM class in SQLAlchemy:
    class Task:
    ....some params..
    __mapper_args__ = dict(polymorphic_on = type)

    2. Anyone who wants to extend this Task class would have to do this:
    class MyTask(Task):
    __mapper_args__ = dict(polymorphic_identity = 'MyTask')

    I do not want to force the consumers of this framework to write this
    obscure line of code. I was wondering if it is possible (at class
    definition time) to capture the fact that MyTask extends Task and
    automatically insert the polymorphic_identity key into the
    __mapper_args__ class attribute (with value set to __name__).

    So far, I have not been able to do anything because during class
    definition time, there is no a lot of variables I can access. *self*
    obviously does not work. __name__ and __class__ are also useless.

    I am thinking, it could be possible if I could write a class wrapper.
    I.e. the consumers would extend a wrapper instead of Task class. This
    wrapper would return a class object with the __mapper_args__. I could
    not find any examples on this topic.

    I would really appreciate your help.
    gizli, Sep 10, 2009
    #1
    1. Advertising

  2. On Wed, 09 Sep 2009 20:14:33 -0700, gizli wrote:

    > I do not want to force the consumers of this framework to write this
    > obscure line of code. I was wondering if it is possible (at class
    > definition time) to capture the fact that MyTask extends Task and
    > automatically insert the polymorphic_identity key into the
    > __mapper_args__ class attribute (with value set to __name__).
    >
    > So far, I have not been able to do anything because during class
    > definition time, there is no a lot of variables I can access. *self*
    > obviously does not work. __name__ and __class__ are also useless.


    Class definitions are controlled by the metaclass, which is fairly deep
    magic but not entirely impenetrable. Once you've defined a metaclass to
    use, the consumers will only need to say:

    class MyTask(Task):
    __metaclass__ = MyMetaclass

    which is less obscure than the alternative. You may even be able to have
    Task use the metaclass, in which case MyTask doesn't need to do anything
    special at all. (I think.)


    Another alternative is to use a class decorator:

    # You write this and provide it in your API.
    def mapper(cls):
    cls.__mapper_args__ = dict(polymorphic_identity=cls.__name__)
    return cls


    # The consumer writes this.
    @mapper
    class MyTask(Task):
    pass


    Decorator syntax for classes only works for Python 2.6 or better. In 2.5,
    the consumer would need to write:

    class MyTask(Task):
    pass
    MyTask = mapper(MyTask)



    --
    Steven
    Steven D'Aprano, Sep 10, 2009
    #2
    1. Advertising

  3. gizli

    gizli Guest

    On Sep 9, 9:00 pm, Steven D'Aprano
    <> wrote:
    > On Wed, 09 Sep 2009 20:14:33 -0700, gizli wrote:
    > > I do not want to force the consumers of this framework to write this
    > > obscure line of code. I was wondering if it is possible (at class
    > > definition time) to capture the fact that MyTask extends Task and
    > > automatically insert the polymorphic_identity key into the
    > > __mapper_args__ class attribute (with value set to __name__).

    >
    > > So far, I have not been able to do anything because during class
    > > definition time, there is no a lot of variables I can access. *self*
    > > obviously does not work. __name__ and __class__ are also useless.

    >
    > Class definitions are controlled by the metaclass, which is fairly deep
    > magic but not entirely impenetrable. Once you've defined a metaclass to
    > use, the consumers will only need to say:
    >
    > class MyTask(Task):
    >     __metaclass__ = MyMetaclass
    >
    > which is less obscure than the alternative. You may even be able to have
    > Task use the metaclass, in which case MyTask doesn't need to do anything
    > special at all. (I think.)
    >
    > Another alternative is to use a class decorator:
    >
    > # You write this and provide it in your API.
    > def mapper(cls):
    >     cls.__mapper_args__ = dict(polymorphic_identity=cls.__name__)
    >     return cls
    >
    > # The consumer writes this.
    > @mapper
    > class MyTask(Task):
    >     pass
    >
    > Decorator syntax for classes only works for Python 2.6 or better. In 2.5,
    > the consumer would need to write:
    >
    > class MyTask(Task):
    >     pass
    > MyTask = mapper(MyTask)
    >
    > --
    > Steven


    Steven, thank you. __metaclass__ was exactly what I was looking for.
    After a few documents later, I came up with this code:

    class PolymorphicSetter(type):
    def __new__(cls, name, bases, dictionary):
    dictionary['__mapper_args__'] = name
    return type.__new__(cls, name, bases, dictionary)

    and set this in my Task class:

    __metaclass__ = PolymorphicSetter

    Also, thank you for the class decorator code. That is what I meant by
    class wrapper :) I will keep that as a reference as well.
    gizli, Sep 10, 2009
    #3
    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. Guest
    Replies:
    1
    Views:
    751
    Guest
    Jun 29, 2004
  2. anon
    Replies:
    6
    Views:
    312
  3. Franck PEREZ

    Automatic class attribute

    Franck PEREZ, Feb 3, 2006, in forum: Python
    Replies:
    2
    Views:
    245
    Franck PEREZ
    Feb 4, 2006
  4. Jon Slaughter
    Replies:
    6
    Views:
    369
    Andy Dingley
    Apr 19, 2007
  5. Bilal
    Replies:
    0
    Views:
    132
    Bilal
    May 17, 2004
Loading...

Share This Page