2009-03-30 26 views
7

Nouveau ici. Aussi je suis (très) nouveau à python et essaye de comprendre le comportement suivant. Quelqu'un peut-il m'expliquer pourquoi les deux méthodes de cet exemple ont des résultats différents?décorateurs et méthodes python

def map_children(method): 
    def wrapper(self,*args,**kwargs): 
     res = method(self,*args,**kwargs) 
     for child in self._children: 
      method(child,*args,**kwargs)    
     return res 
    return wrapper 

class Node(object): 

    def __init__(self,name,parent=None): 
     self._namestring = name 
     if parent: 
      self._parent = parent 

     self._children = [] 

    @map_children 
    def decorated(self): 
     if hasattr(self,'_parent'): 
      print '%s (child of %s)'%(self._namestring,self._parent._namestring) 
     else: 
      print '%s'% self._namestring 

    def undecorated(self): 
     if hasattr(self,'_parent'): 
      print '%s (child of %s)'%(self._namestring,self._parent._namestring) 
     else: 
      print '%s'% self._namestring 

     for child in self._children: 
      child.undecorated() 


def runme(): 
    parent = Node('parent') 

    child1 = Node('child1',parent) 
    child2 = Node('child2',parent) 
    grandchild = Node('grandchild',child1) 
    child1._children.append(grandchild) 
    parent._children.append(child1) 
    parent._children.append(child2) 

    print '**********result from decorator**********' 
    parent.decorated() 

    print '**********result by hand**********' 
    parent.undecorated() 

Voici la sortie sur mon système:

 
In[]:testcase.runme() 
**********result from decorator********** 
parent 
child1 (child of parent) 
child2 (child of parent) 
**********result by hand********** 
parent 
child1 (child of parent) 
grandchild (child of child1) 
child2 (child of parent) 

Alors, pourquoi ne l'appel jamais décoré descendre au nœud petit-enfant? Je suis évidemment manque quelque chose sur la syntaxe ...

Répondre

7

Dans le décorateur, vous êtes bouclez les enfants de noeud et d'appeler la originale, non récurrente method sur les

method(child, *args, **kwargs) 

de sorte que vous » Je vais seulement un niveau profond. Essayez de remplacer cette ligne par

map_children(method)(child, *args, **kwargs) 

et vous obtiendrez la même sortie que la version récursive manuelle.

+1

Merci! Je savais que ça devait être quelque chose comme ça. J'ai essayé ceci avec la notation de @ mais cela n'a pas fonctionné (évidemment), et je ne trouvais pas la bonne syntaxe. Ensuite, j'ai réussi à me convaincre que la méthode était en train de se transformer, ce qui ne devrait donc pas avoir d'importance. Je dois arrêter de penser à cela comme des macros "correctes". –

+0

Je pense que cette approche ne fera pas ce que vous attendez si Node est sous-classé et que la sous-classe a sa propre version de la méthode ... – simon