2009-03-30 14 views
7

Novità qui. Inoltre sono (molto) nuovo in Python e sto cercando di capire il seguente comportamento. Qualcuno può spiegarmi perché i due metodi in questo esempio hanno un output diverso?decoratori e metodi di pitone

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() 

Ecco l'output sul mio sistema:

 
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) 

Allora perché la chiamata decorato mai scendere al nodo nipotino? Sono ovviamente manca qualcosa sulla sintassi ...

risposta

7

Nel decoratore, si sono ciclare su figli del nodo e chiamando il originale, non ricorsiva method su di loro

method(child, *args, **kwargs) 

in modo da' andremo solo a un livello di profondità. Prova a sostituire quella linea con

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

e otterrai lo stesso risultato della versione ricorsiva manuale.

+1

Grazie! Sapeva che doveva essere qualcosa del genere. Ho provato questo con la notazione @ ma non ha funzionato (ovviamente), e non ho trovato la sintassi giusta. Poi sono riuscito a convincermi che stava trasformando il metodo attuale, quindi non dovrebbe importare. Devo smettere di pensarlo come "corretto" macro. –

+0

Penso che questo approccio non farà quello che ti aspetti se Node è sottoclasse e la sottoclasse ha la sua versione del metodo ... – simon