我正在使用来自SO问题:Python file parsing: Build tree from text file的函数从文本文件输入中创建树结构。但是我只能通过使用全局变量来生成我的树,并且无法找到避免这种情况的方法。
在名为data.txt
的文件中,我有以下内容:
Root
-A 10
-B
--B A 2
--B B 5
--B Z 9
--B X
---X 4
---Y
----Y0 67
----Y1 32
---Z 3
-C 19
{'B': ['B A 2', 'B B 5', 'B Z 9', 'B X'],
'B X': ['X 4', 'Y', 'Z 3'],
'Root': ['A 10', 'B', 'C 19'],
'Y': ['Y0 67', 'Y1 32']}
import re, pprint
PATTERN = re.compile('^[-]+')
tree = {}
def _recurse_tree(parent, depth, source):
last_line = source.readline().rstrip()
while last_line:
if last_line.startswith('-'):
tabs = len( re.match(PATTERN, last_line).group() )
else:
tabs = 0
if tabs < depth:
break
node = re.sub(PATTERN, '', last_line.strip())
if tabs >= depth:
if parent is not None:
print "%s: %s" %(parent, node)
if parent in tree:
tree[parent].append(node)
else:
tree[parent] = [ node, ]
last_line = _recurse_tree(node, tabs+1, source)
return last_line
def main():
inFile = open("data.txt")
_recurse_tree(None, 0, inFile)
pprint.pprint(tree)
if __name__ == "__main__":
main()
如何摆脱全局变量tree
?我所做的一切似乎都使代码更长或更丑,但我想大量使用这个功能,我讨厌取决于核心结果的副作用。
在下面的答案之后,我修改了代码,以下列方式返回tree
。这是pythonic吗?返回一个元组,然后抛出第一个元素似乎不够优雅。
def _recurse_tree(parent, depth, source, tree=None):
if tree is None:
tree = {}
last_line = source.readline().rstrip()
while last_line:
if last_line.startswith('-'):
tabs = len( re.match(PATTERN, last_line).group() )
else:
tabs = 0
if tabs < depth:
break
node = re.sub(PATTERN, '', last_line.strip())
if tabs >= depth:
if parent is not None:
print "%s: %s" %(parent, node)
if parent in tree:
tree[parent].append(node)
else:
tree[parent] = [ node, ]
last_line, tree = _recurse_tree(node, tabs+1, source, tree)
return last_line, tree
def main():
inFile = open("data.txt")
tmp, tree = _recurse_tree(None, 0, inFile)
pprint.pprint(tree)
答案 0 :(得分:4)
您的tree
变量已经是可变的;只需将它与递归调用一起传递:
def _recurse_tree(parent, depth, source, tree=None):
if tree is None:
tree = {}
last_line = source.readline().rstrip()
while last_line:
if last_line.startswith('-'):
tabs = len( re.match(PATTERN, last_line).group() )
else:
tabs = 0
if tabs < depth:
break
node = re.sub(PATTERN, '', last_line.strip())
if tabs >= depth:
if parent is not None:
print "%s: %s" %(parent, node)
if parent in tree:
tree[parent].append(node)
else:
tree[parent] = [ node, ]
last_line = _recurse_tree(node, tabs+1, source, tree)
return last_line
或者,您可以使用类来保存状态,然后从实例中获取状态会更容易:
class TreeBuilder(object):
_PATTERN = re.compile('^[-]+')
def __init__(self, source):
self.tree = {}
self.source = source
self._recurse_tree()
def _recurse_tree(self, parent=None, depth=0):
last_line = self.source.readline().rstrip()
while last_line:
if last_line.startswith('-'):
tabs = len( self._PATTERN.match(last_line).group() )
else:
tabs = 0
if tabs < depth:
break
node = self._PATTERN.sub('', last_line.strip())
if tabs >= depth:
if parent is not None:
print "%s: %s" %(parent, node)
if parent in self.tree:
self.tree[parent].append(node)
else:
self.tree[parent] = [ node, ]
last_line = self._recurse_tree(node, tabs+1)
return last_line
然后像这样使用:
def main():
inFile = open("data.txt")
builder = TreeBuilder(inFile)
pprint.pprint(builder.tree)
答案 1 :(得分:1)
我认为这里的解决方案很好 - 创建类并将树放入内部,就像私有类成员一样。
或者您可以简单地将此字典作为函数中的一个参数传递,并在递归期间传递它。它将通过引用传递,因此所有时间函数将使用没有全局变量的相同字典。但我更喜欢上课。
答案 2 :(得分:0)
在您的函数中使用tree
作为默认参数: -
def _recurse_tree(parent, depth, source, tree = None):
if tree is None: # needed on first invocation
tree = {}
在没有tree
参数的情况下第一次调用它,并在每次连续调用时,向其添加另一个参数tree
。
因此,从您的方法内部,您的递归调用变为: -
last_line = _recurse_tree(node, tabs+1, source, tree)