Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Automatic Attribute Assignment during Class Inheritance

Reply
Thread Tools

Automatic Attribute Assignment during Class Inheritance

 
 
gizli
Guest
Posts: n/a
 
      09-10-2009
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.
 
Reply With Quote
 
 
 
 
Steven D'Aprano
Guest
Posts: n/a
 
      09-10-2009
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
 
Reply With Quote
 
 
 
 
gizli
Guest
Posts: n/a
 
      09-10-2009
On Sep 9, 9:00*pm, Steven D'Aprano
<ste...@REMOVE.THIS.cybersource.com.au> 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.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
C++ Struct inheritance against class inheritance johnsonlau C++ 1 07-21-2008 04:58 PM
class attribute selection and assignment Jon Slaughter HTML 6 04-19-2007 10:36 AM
Inheritance error: class Foo has no attribute "bar" crystalattice Python 5 07-12-2006 11:11 PM
Automatic class attribute Franck PEREZ Python 2 02-04-2006 03:44 AM
attribute assignment effects all class instances anon Python 6 09-10-2004 07:51 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57