Python树实现 - 节点引用

时间:2015-11-22 07:37:34

标签: python tree

我有这个代码在Python中实现一个树。其中一个功能是找到下面所有节点(包括它自身)的值的总和,但这不起作用。

我认为原因是,一旦我创建了一个节点,我就无法返回并使用Node(名称,值)访问它 - 这将创建一个具有该名称和值的新节点,而不是指代树中有一个具有该名称和值的子项,其中有子项链接到它。

因此,sum_below函数只返回节点的值。我如何引用树中的节点:

class Node(object):
    def __init__(self, name, value):
        self.name = name
        self.value = value
        self.children = []

    def add_child(self, obj):
        self.children.append(obj)

    def sum_below(self):
        if self.children == []:
            return self.value
        else:
            ret = self.value
            for child in self.children:
                ret += child.sum_below()
            return ret
    def __str__(self, level = 0):
        ret = "\t"*level+repr(self.value)+"\n"
        for child in self.children:
            ret += child.__str__(level+1)
        return ret

[编辑]我的问题是,一旦我创建了一个节点,我就无法引用它:

#In [2]:

Node(1,100)
parent = Node(1,100)
child = Node(2, 200)
parent.add_child(child)

#In [5]:

print parent

#Out [5]:

100
    200

#In [6]:

print Node(1,100)

#Out [6]:

100

所以你看,父节点和节点(1,100)没有引用相同的东西。

[编辑]

#In [5]:
parent.sum_below()
#Out[5]:
300
#In [6]:
Node(1,100).sum_below()
#Out[6]:
100

在上面的代码中,Node(1,100).sum_below()应该等于parent.sum_below(),因为它们应该引用同一个节点,但它们不是。

2 个答案:

答案 0 :(得分:2)

代码似乎没问题。我看到的唯一“不完美”是特殊情况:

if self.children == []: ...
根本不需要

。简化版:

def sum_below(self):
    ret = self.value
    for child in self.children:
        ret += child.sum_below()
    return ret

也会奏效。使用sum

也可以进一步简化它
def sum_below(self):
    return (self.value +
            sum(child.sum_below() for child in self.children))

答案 1 :(得分:0)

此答案仅指您需要通过指定名称来引用前一个实例的部分(假设最多有一个节点具有相同的名称)。

我的建议是你试用元类。 我知道这在Python中是一个有争议的问题,但我认为值得了解。 此外,我认为有更好,更pythonic的方式这样做,但尽管如此,这是我的解决方案.. 下一个代码片段可能会起作用。 (没检查!我正在用手机写字。可能需要进行小的调整。)

Class Metanode(object):
    __nodes = {}

def __new__(cls,name,val):
    if name not in Metanode.__nodes.keys():
        Metanode.__nodes[name] = object.__new__(cls,name,val)
    return Metanode.__nodes[name]

然后将其添加为元类:

class Node(metaclass=Metanode,object):
    ''' put rest of your def here '''
    pass

现在您的元类包含实例字典。每当您创建名为“x”的新实例时,您将获得以该名称命名的最后一个实例。 当然,您还需要在元类中处理这些实例的销毁(因此字典将不具有指向不存在的实例的键)。

修改: 在我的计算机中正确查看代码后,此代码不起作用。然而,下一段代码完全不涉及元类将会起作用(在我的Ubuntu机器上使用python3进行检查):

class Node(object):
    nodes={}

    def new_init(self,name,val):
        self.name = name
        self.val = val
        self.children = [ ]

    def __new__(cls,name,val,*args,**kwds):
        if name not in Node.nodes.keys():
            Node.nodes[name] = super(Node,cls).__new__(cls,*args,**kwds)
            Node.nodes[name].new_init(name,val)
        return Node.nodes[name]

    def __init__(self,name,val):
        pass

    def sum_below(self):
        return self.val + sum(child.sum_below() for child in self.children)

    def add_child(self,node):
        if not isinstance(node,Node):
            '''raise-some-exception-or-whatnot'''
        self.children.append(node)