试图理解奇怪的递归/ObjectAttribute/Scope“明白了”

2024-06-08 12:39:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我只是花了几个小时的时间在思考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还很陌生,我正在努力让这成为一次学习的经历。任何帮助都将不胜感激。你知道吗


Tags: nameselfchildtreefordefcounterpprint
2条回答

问题是函数的默认参数(并且__init__()不是免除的)只创建一次。换句话说,每次创建一个新的DecisionTree时,您都在重用相同的dict对象。你知道吗

你需要做的是:

class DecisionTree:

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

为了解决您的问题,我建议将默认参数children初始化为None,并使用如下行: 自我保护儿童=children或dict()

问题是,在Python中,函数参数是通过引用传递的,具有可变值(字典也是可变的)的默认参数是在函数定义时(仅一次)计算的,而不是在每次调用函数时计算的,结果是每次调用函数dict()时都会返回相同的引用。 常见的Python陷阱。你知道吗

相关问题 更多 >