views:

877

answers:

1

Hi. New here. Also I'm (very) new to python and trying to understand the following behavior. Can someone explain to me why the two methods in this example have different output?

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

Here is the output on my system:

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)

So why does the decorated call never descend to the grandchild node? I'm obviously missing something about the syntax...

+3  A: 

In the decorator, you are looping over the node's children and calling the original, non-recursive method on them

method(child, *args, **kwargs)

so you'll only go one level deep. Try replacing that line with

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

and you'll get the same output as the manual recursive version.

dF
Thanks! Knew it had to be something like that. I tried this with the @ notation but it didn't work (obviously), and I coudn't find the right syntax. Then I managed to convince myself it was transforming the actual method, so shouldn't matter. I've got to stop thinking of it like "proper" macros.
I think this approach won't do what you expect if Node is subclassed and the subclass has it's own version of the method...
simon