我花了好几个小时在python中讨论以下问题,我无法弄清楚它为什么会发生。
说我正在做决策树类:
class DecisionTree:
def __init__(self, name, children = dict()):
self.name = name
self.children = children # <------- here's the problem
def add_child(self, child_name, child_tree):
self.children[child_name] = child_tree
def pprint(self, depth = 0):
for childkey in self.children:
tabs = " ".join(["\t" for x in xrange(depth)])
print tabs + 'if ' + self.name + ' is ' + str(childkey)
if (self.children[childkey].__class__.__name__ == 'DecisionTree'): # this is a tree, delve deeper
print tabs + 'and...'
child = self.children.get(childkey)
child.pprint(depth + 1 )
else:
val = self.children.get(childkey)
print tabs + 'then predict ' + str( val )
print "\n"
return ''
现在让我们构建一个无意义的树,并尝试打印它:
def make_a_tree(depth = 0, counter = 0):
counter += 1
if depth > 3:
return 'bottom'
else:
tree = DecisionTree(str(depth)+str(counter))
for i in range(2):
subtree = make_a_tree(depth+1, counter)
tree.add_child(i, subtree)
return tree
foo = make_a_tree()
foo.pprint()
此代码导致无限递归循环,因为树结构(以某种方式)错误地构建了树的第二个节点引用自身。
如果我将上面标记的行(第5行)更改为tree.children = dict()
,那么一切正常。
我无法理解这里发生的事情。编写代码背后的意图是为“children”创建一个参数,如果没有传递,则创建一个空字典并将其用作子代。
我对Python很陌生,我正在努力使这成为一种学习体验。任何帮助将不胜感激。
答案 0 :(得分:1)
问题是函数的默认参数(和__init__()
不是免除的)创建一次。换句话说,每次创建新的dict
时,您都会重复使用相同的DecisionTree
对象。
您需要做的是:
class DecisionTree:
def __init__(self, name, children = None):
self.name = name
if children is None:
children = {}
self.children = children
答案 1 :(得分:0)
作为您问题的解决方案,我建议将默认参数children初始化为None,并且有一行如下: self.children =孩子或dict()
问题是在Python中,函数参数通过引用传递,并且具有可变值(和字典是可变的)的默认参数在函数定义时(仅一次)评估,而不是在函数的每次调用时得到,每次调用函数时dict()都会返回相同的引用。 常见的python陷阱。