试图理解奇怪的递归/对象属性/范围“得到”

时间:2015-04-28 19:09:46

标签: python object recursion scope

我花了好几个小时在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很陌生,我正在努力使这成为一种学习体验。任何帮助将不胜感激。

2 个答案:

答案 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陷阱。