2010-06-09 5 views
3

J'essaie de définir un décorateur de classe. J'ai un problème avec la méthode __init__ en classe décorée. Si la méthode __init__ invoque super la RuntimeErrorprofondeur de récursivité maximale dépassée est élevée.Décorateur de classe Python et profondeur de récursivité maximale dépassée

Exemple de code:

def decorate(cls): 
    class NewClass(cls): pass 
    return NewClass 

@decorate 
class Foo(object): 
    def __init__(self, *args, **kwargs): 
     super(Foo, self).__init__(*args, **kwargs) 

Qu'est-ce que je fais mal?

Merci, Michał

Modifier 1

Merci à Mike réponse boers je me suis rendu à cette question est correcte que dois-je faire pour que achive super (Foo, auto) pointer à la classe appropriée.

J'ai aussi deux limitations. Je veux appeler la méthode Foo.__init__ et je ne peux pas modifier la définition de classe Foo.

Edit 2

J'ai résolu ce problème. Je modifie le corps de la fonction décorateur. Je ne retourne pas de nouvelle classe. Au lieu d'envelopper des méthodes de classe orginal.

+0

double possible de [classe, héritage, décorateurs super(), et la récursivité maximale] (http://stackoverflow.com/questions/2542747/class-decorators-inheritance-super-and-maximum-recursion) –

+0

Comment pouvez-vous appliquer un décorateur à la classe Foo mais vous ne pouvez pas changer sa définition? –

+0

J'écris ajax validation django app. Il devrait être générique et ne nécessite pas de changements dans la définition de classe de formulaire. –

Répondre

4

Vous devez remplacer NewClass.__init__ pour empêcher la récursivité, car NewClass.__init__ est Foo.__init__ et il continue à s'appeler.

def decorate(cls): 
    class NewClass(cls): 
     def __init__(self): 
      pass 
    return NewClass 

Nouvelle idée:

Que diriez-vous pas sous-classer? Peut-être que le patch de singe est votre ami?

def decorate(cls): 
    old_do_something = cls.do_something 
    def new_do_something(self): 
     print "decorated", 
     old_do_something(self) 

    cls.do_something = new_do_something 
    return cls 

@decorate 
class Foo(object): 
    def __init__(self, *args, **kwargs): 
     super(Foo, self).__init__(*args, **kwargs) 

    def do_something(self): 
     print "Foo" 

f = Foo() 
f.do_something() 
+0

Ok, mais je veux exécuter la méthode Foo .__ init__. Je ne peux pas éditer la définition de classe Foo. –

+0

Oui, cela fonctionne très bien. –

+0

Souhait "pas sous-classe" était une réponse distincte afin que je puisse +1 au-dessus de la modification de la classe réelle (qui ne fonctionne pas dans de nombreux cas). – claytond

3

Rappelez-vous qu'un décorateur est tout simplement le sucre syntaxique pour:

>>> Foo = decorate(Foo) 

Donc, dans ce cas, le nom Foo fait référence à la classe NewClass. Dans la méthode Foo.__init__ vous demandez en fait le super __init__ de NewClass, qui est Foo.__init__ (qui est ce qui est en cours d'exécution).

Ainsi, votre Foo.__init__ continue de recevoir son propre __init__ pour appeler, et vous vous retrouvez dans une récursion infinie.

Questions connexes