微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

用于创建字典的函数中的默认参数会创建一个无限循环的自引用

如何解决用于创建字典的函数中的默认参数会创建一个无限循环的自引用

以下代码有问题:

from lxml import etree as ET

class test(object):
    def __init__(self,**args):
        self.tag = []
        self.meshfiles = []
        self.root = None
    def addMesh(self,**args):
        if not "filename" in args:
            raise KeyError("No filename given")
        else:
            self.meshfiles.append(args["filename"])
    def populateTree(self,tag,text='',attr={},children={}):
        return {'tag': tag,'text': text,'attr': attr,'children': children}

    @property
    def tree(self):
        baum = {'meshes': {}}
        if len(self.meshfiles) == 1:
            baum['meshes'] = self.populateTree('mesh',text=self.meshfiles[0])
        else:
            baum['meshes'] = self.populateTree('meshes')
            for i,meshfile in enumerate(self.meshfiles):
                # works:
                baum['meshes']['children'][i] = self.populateTree('mesh',text=meshfile)
                # not working:
                # baum['meshes']['children'][i] = self.populateTree('mesh',text=meshfile,children={})
        return baum

    def createXML(self):
        self.root = ET.Element("rootelement")
        self.dict2xml(self.root,self.tree)
        return ET.tostring(self.root,pretty_print=True)
    def dict2xml(self,parent,dictionary):
        for entry in dictionary:
            self.tag.append(ET.SubElement(parent,dictionary[entry]['tag']))
            self.tag[-1].text = str(dictionary[entry]['text'])
            for attr in dictionary[entry]['attr']:
                self.tag[-1].set(attr,dictionary[entry]['attr'][attr])
            if len(dictionary[entry]['children']) > 0:
                self.dict2xml(self.tag[-1],dictionary[entry]['children'])
if __name__ == "__main__":
    t = test()
    t.addMesh(filename="a")
    t.addMesh(filename="c")
    t.addMesh(filename="b")
    print(t.tree)
    print(t.createXML())

虽然这个例子给出了递归错误

    {'meshes': {'tag': 'meshes','text': '','attr': {},'children': {0: {'tag': 'mesh','text': 'a','children': {...}},1: {'tag': 'mesh','text': 'c',2: {'tag': 'mesh','text': 'b','children': {...}}}}}
Traceback (most recent call last):
  File "/home/buchwalj/temp/bug-python/test.py",line 48,in <module>
    print(t.createXML())
  File "/home/buchwalj/temp/bug-python/test.py",line 32,in createXML
    self.dict2xml(self.root,self.tree)
  File "/home/buchwalj/temp/bug-python/test.py",line 41,in dict2xml
    self.dict2xml(self.tag[-1],dictionary[entry]['children'])
  File "/home/buchwalj/temp/bug-python/test.py",dictionary[entry]['children'])
  [PrevIoUs line repeated 994 more times]
  File "/home/buchwalj/temp/bug-python/test.py",line 36,in dict2xml
    self.tag.append(ET.SubElement(parent,dictionary[entry]['tag']))
 RecursionError: maximum recursion depth exceeded while calling a Python object

注释掉第 27 行而不是第 25 行会打印出带有相应 xml 的正确字典。唯一的区别是,工作示例使用与函数调用中的认参数相同的参数,而不是认参数本身。 这是一个错误还是我在这里做错了什么?

解决方法

使用空字典作为默认值实际上是个坏主意,主要是因为字典是可变对象,这意味着如果您不小心更改了字典的内容,它会留在那里(因为对对象的引用保持不变)。请参阅:Why is the empty dictionary a dangerous default value in Python?

我建议将您的 populateTree 函数更改为:

def populateTree(self,tag,text='',attr=None,children=None):
        if attr is None:
            attr = {}
        if children is None:
            children = {}
        return {'tag': tag,'text': text,'attr': attr,'children': children}

因此它创建了一个新的空字典,所有 populateTree 都在没有这些参数的情况下被调用。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。