所以这是我的代码,我想要制作一个简单的节点树:
class Node(object):
child = []
def __init__(self,id):
self.id =id
def addChild(self,child):
self.child.append(child)
def printChildOnwards(self):
yield self.id
for x in self.child:
yield from x.printChildOnwards()
firstChild = Node('1')
secondChild = Node('2')
thirdChild = Node('3')
fourthChild = Node('4')
firstChild.addChild(secondChild)
firstChild.addChild(thirdChild)
for x in firstChild.printChildOnwards():
print(x)
我已经通过self
访问了已定义的类级属性,以确保我访问自己的版本。
输出:
1 2 2 2 2 ... then recursion error max depth
虽然我可以在__init__
内简单地定义它,但是它有效
self.child = []
输出:1 2 3
这种行为背后的原因是什么?为什么我需要将其包含在__init__
?
答案 0 :(得分:1)
在您的初始示例中:
class Node(object):
child = []
def __init__(self, id):
self.id = id
child
属性是Node
类的类级别属性,这意味着Node
的每个实例都将共享该对象,因此每次迭代都会printChildOnwards
呼叫只会从同一列表中继续打印。正如您所发现的那样,在__init__
方法中定义它会起作用,因为它为每个实例创建了一个实例级child
属性,因此它们现在都是唯一的,并且不会导致迭代通过相同的共享列表孩子们。
您可以使用id
函数轻松验证任何对象的标识(内存地址)。有了它,您可以自己看到使用此示例的子属性是相同的:
>>> n1 = Node(1)
>>> n2 = Node(2)
>>> id(n1.child)
139928077828744
>>> id(n2.child)
139928077828744
将其更改回您修复的版本:
class Node(object):
def __init__(self, id):
self.child = []
self.id = id
再次使用id
功能再次验证并发现它们不同。
>>> n1 = Node(1)
>>> n2 = Node(2)
>>> id(n1.child)
139928077829192
>>> id(n2.child)
139928077828936