我正在用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()
答案 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 = []