试图理解怪异 Recursion/Object-Attribute/Scope "Gotcha"

Trying to Understand Weird Recursion/Object-Attribute/Scope "Gotcha"

我刚刚花了几个小时思考 python 中的以下问题,我不太明白为什么会这样。

说我正在做决策树 class:

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" 取一个参数,如果传递了 none,则创建一个空字典并将其用作子字典。

我是 Python 的新手,我正在努力使它成为一种学习体验。任何帮助将不胜感激。

问题是函数的默认参数(__init__() 也不例外)只创建一次。换句话说,每次创建新的 DecisionTree.

时,您都在重复使用相同的 dict 对象

你需要做的是:

class DecisionTree:

def __init__(self, name, children = None):
    self.name = name
    if children is None:
        children = {}
    self.children = children

作为您问题的解决方案,我建议将默认参数 children 初始化为 None,并有如下一行: self.children = children 或 dict()

问题是在 Python 中,函数参数是通过引用传递的,具有可变值(和字典是可变的)的默认参数在函数定义时(仅一次)而不是每次都被评估调用函数导致每次调用 dict() 时都会 return 相同的引用。 常见 python 陷阱。