用于创建字典的函数中的默认参数会创建一个无限循环的自引用
default argument in function for creating a dictionary creates an infinete loop of self references
a 有以下代码的问题:
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', 'attr': {}, 'children': {...}}, 1: {'tag': 'mesh', 'text': 'c', 'attr': {}, 'children': {...}}, 2: {'tag': 'mesh', 'text': 'b', 'attr': {}, '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", line 41, in dict2xml
self.dict2xml(self.tag[-1], dictionary[entry]['children'])
File "/home/buchwalj/temp/bug-python/test.py", line 41, in dict2xml
self.dict2xml(self.tag[-1], 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
都在没有这些参数的情况下被调用。
a 有以下代码的问题:
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', 'attr': {}, 'children': {...}}, 1: {'tag': 'mesh', 'text': 'c', 'attr': {}, 'children': {...}}, 2: {'tag': 'mesh', 'text': 'b', 'attr': {}, '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", line 41, in dict2xml
self.dict2xml(self.tag[-1], dictionary[entry]['children'])
File "/home/buchwalj/temp/bug-python/test.py", line 41, in dict2xml
self.dict2xml(self.tag[-1], 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
都在没有这些参数的情况下被调用。