使用简单树类的意外行为

时间:2013-09-18 23:15:37

标签: python

我正在用python编写一个学习程序,我没有得到我期待的行为。我试图用一个名为node的类创建一个非常基本的树。请不要因为设计糟糕的树而惩罚我,我只是想学习语言。

无论如何,我期待输出如下:

LEVEL1 0
LEVEL1 1

但是,我正在

LEVEL1 0
LEVEL1 1
LEVEL1 0 ... LEVEL2 0

在我所做的行leaves[0].addLeaf我真的以为我会调用其中一个子叶的方法,但看起来我是从TOP叶子调用的。请帮我理解。

不要被traversePrint这个名字欺骗。什么都没有被遍历,不管怎么说:(

#!/usr/bin/python

class node:
    """Something that can act like like leaves of a tree"""
    leaves = []
    def __init__(self, data=""):
        self.data = data
    def addLeaf(self, newNode="new"):
        self.leaves.append(node(newNode))
    def printLeafs(self):
        for leaf in self.leaves:
            print leaf.data
    def getLeafs(self):
        return self.leaves
    def traversePrint(self):
        for leaf in self.leaves:
            print leaf.data
        #for leaf in self.leaves:
        #   leaf.traversePrint()

top = node("TOP")
top.addLeaf("LEVEL1 0")
top.addLeaf("LEVEL1 1")

leaves = top.getLeafs()
leaves[0].addLeaf("LEVEL1 0 ... LEVEL2 0")

top.traversePrint()

3 个答案:

答案 0 :(得分:4)

您的问题是,leaves类级别属性。您希望它是实例级属性,以便不在所有实例之间共享列表。有关差异的详细信息,请参阅this SO question

幸运的是,将leaves设为实例属性很容易:删除第leaves = []行,改为将__init__方法更改为包含第self.leaves = []行。

def __init__(self, data=""):
    self.data = data
    self.leaves = [] # Create a new list to hold this instance's children!

要更清楚地了解原始代码中的内容,请在添加叶子后添加addLeaf来编辑print([leaf.data for leaf in self.leaves])方法。在您的原始代码中,这将打印出来:

['LEVEL1 0']
['LEVEL1 0', 'LEVEL1 1']
['LEVEL1 0', 'LEVEL1 1', 'LEVEL1 0 ... LEVEL2 0']

当然,你只想在第三个打印输出上显示一个叶子,因为你正在访问一个不同的节点,而是你得到了所有三个!这是因为当列表位于类级别时,node的所有实例共享相同的leaves列表。当您在__init__方法中移动列表初始化时,您会看到三个addLeaf调用的预期结果:

['LEVEL1 0']
['LEVEL1 0', 'LEVEL1 1']
['LEVEL1 0 ... LEVEL2 0']

答案 1 :(得分:3)

由于您在班级定义leaves,因此node所有实例共享一个leaves列表。我怀疑这是你的意图。如果您希望每个node都有拥有 leaves列表,请将作业转移到__init__

    # leaves = [] # REMOVE THIS LINE
    def __init__(self, data=""):
        self.data = data
        self.leaves = []  # ADD THIS LINE

然后输出是:

LEVEL1 0
LEVEL1 1

并添加:

leaves[0].traversePrint()

打印:

LEVEL1 0 ... LEVEL2 0

清除?

答案 2 :(得分:2)

leaves是一个类属性,因此所有addLeaf都会添加到该单个属性,因为所有节点都是类node的对象(顺便说一下,将其重命名为Node)

您想要的是每个节点属性离开,因此将其添加为实例属性,即在__init__添加self.leaves = []