Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python dynamically create class with inner class

I'm using django-tastypie and I need to create classes like this from my django models:

class MyModelResource(ModelResource):
    class Meta:
        queryset = MyModel.objects.all()
        allowed_methods = ['get']

Since I have a lot of models in my django app I don't want to repeat myself, and use type() function instead to create all that resource classes. The problem is I don't know how to deal with this inner "Meta" class.

Can you give me an example of how to dynamically create a class with inner class using type()?

like image 580
mnowotka Avatar asked Nov 27 '12 16:11

mnowotka


1 Answers

class MyModel(object) : pass
modelClass = MyModel()

class ModelResource(object):
    def mymethod(self):
        print('got here')

Meta = type('Meta', (object, ), {'allowed_methods': ['get']})

def add_mymethod(cls):
    def mymethod(self):
        super(cls, self).mymethod()
    cls.mymethod = mymethod
    return cls

name = modelClass.__class__.__name__ + "Resource"
MyModelResource = add_mymethod(type(name, (ModelResource, ),
                                    {'Meta':Meta, }))

print(MyModelResource.Meta)
# <class '__main__.Meta'>

m = MyModelResource()
m.mymethod()
# got here

The inner class, Meta, is just another attribute as far as MyModelResource is concerned.


Methods are also just attributes as far as MyModelResource is concerned. Actually, you define a function in MyModelResource.__dict__, and the Python attribute lookup mechanism causes inst.mymethod to return a bound method.

There is no problem referring to MyModelResource in the super call

super(MyModelResource, self).mymethod()

before MyModelResource is defined, because name lookups are performed at run time, not at the time mymethod is defined.


You are absolutely correct that

super(self.__class_, self).mymethod()

is wrong. This will spoil all that is good about super. If MyModelResource were to be subclassed, and an instance of the subclass were to call mymethod, then Python would fall into an infinite loop.

like image 92
unutbu Avatar answered Oct 08 '22 07:10

unutbu