2012-11-27 12 views
5

Ich verwende django-tastypie und ich brauche Klassen wie dies aus meinen django Modellen zu erstellen:Python dynamisch Klasse mit innerer Klasse erstellen

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

Da ich viele Modelle in meinem django app Ich habe don Ich möchte mich nicht wiederholen und stattdessen die type() - Funktion verwenden, um alle diese Ressourcenklassen zu erstellen. Das Problem ist, dass ich nicht weiß, wie ich mit dieser inneren "Meta" -Klasse umgehen soll.

Können Sie mir ein Beispiel geben, wie man dynamisch eine Klasse mit innerer Klasse mit type() erstellt?

Antwort

7
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 

Die innere Klasse, Meta, ist nur ein weiteres Attribut so weit wie MyModelResource betrifft.


Methoden sind auch so weit nur Attribute wie MyModelResource betroffen ist. Tatsächlich definieren Sie eine Funktion in MyModelResource.__dict__, und der Python-Attribut-Lookup-Mechanismus verursacht inst.mymethod, um eine gebundene Methode zurückzugeben.

Es gibt kein Problem zu MyModelResource im super Aufruf bezieht

super(MyModelResource, self).mymethod() 

vor MyModelResource definiert ist, weil Name Lookups zur Laufzeit durchgeführt wird, nicht zu dem Zeitpunkt mymethod definiert ist.


Sie sind absolut richtig, dass

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

falsch ist. Dies verderbt alles, was gut ist über super. Wenn MyModelResource Unterklasse sein sollte und eine Instanz der Unterklasse mymethod aufrufen sollte, würde Python in eine Endlosschleife fallen.

+0

Dies ist die richtige Antwort. Was nun, wenn ich eine Methode definieren muss, die super() aufruft? Ich möchte vermeiden, super (selbst .__ class__, self) zu schreiben, weil anscheinend keine gute Idee ist ... – mnowotka

+0

das Problem ist, ich weiß nicht, Name der Klasse im Moment der Definition der Methode. In meinem Fall sieht die Erstellung der Klasse folgendermaßen aus: type (modelClass .__ class __.__ name__ + "Resource", (ModelResource,), {"Meta" ... also kann ich in der Methode nicht mit dem Namen darauf verweisen. – mnowotka

+0

Okay, so 'mymethod' kann erst definiert werden, nachdem'MyModelResource' definiert wurde.In diesem Fall benutze einen Klassendekorator.Ich habe als Beispiel den Klassendekorator' add_mymethod' hinzugefügt. – unutbu