我正在尝试使用Python 3.5中的递归循环来存储测试软件中的数据。
我不明白的是为什么Python不返回递归调用的第一个调用并继续循环。
我有一系列这样的词典:
testSuites = [{'id': '278', 'parent_id': '213', 'name': 'Initial release'}, {'id': '281', 'parent_id': '279', 'name': 'Screening'}, {'id': '279', 'parent_id': '278', 'name': 'Web'}, {'id': '282', 'parent_id': '213', 'name': 'Initial release'}]
我想拥有一个TestSuite对象,该对象将具有一组TestSuite子代,每个子代都有自己的子代子集(如一棵树)。
root (TestSuite, id=213)
.array[ child1 (TestSuite, id=278), child2 (TestSuite, id=282) ]
child1 (TestSuite, id=278)
.array[ child11 (TestSuite, id=279) ]
child11 (TestSuite, id=279)
.array[ child111 (TestSuite, id=281) ]
在以下情况下会发生扭曲:
testSuites = [{'id': '278', 'parent_id': '213', 'name': 'Initial release'}, {'id': '281', 'parent_id': '279', 'name': 'Screening'}, {'id': '279', 'parent_id': '278', 'name': 'Web'}, {'id': '282', 'parent_id': '213', 'name': 'Initial release'}, {'name': 'Initial release', 'parent_id': '213', 'id': '283'}, {'name': 'Screening', 'parent_id': '283', 'id': '284'}]
我期望以下几点:
root (TestSuite, id=213)
.array[ child1 (TestSuite, id=278), child2 (TestSuite, id=282), child3 (TestSuite, id=283) ]
child1 (TestSuite, id=278)
.array[ child11 (TestSuite, id=279) ]
child11 (TestSuite, id=279)
.array[ child111 (TestSuite, id=281) ]
child2 (TestSuite, id=282)
.array[]
child3 (TestSuite, id=283)
.array[ child31 (TestSuite, id=284) ]
我需要将它们作为数组(或者我可以变成数组的东西),因为我需要将结果提供给可以遍历数组以填充文档的库。
我有一个简单的TestSuite
类,它表示上图中的每个节点:
class TestSuite:
def __init__(self, testsuite_id = None):
self.testsuite_id = testsuite_id
self.hasChild = False
self.child = None
然后我使用一个函数(我留下了调试消息以了解我正在接收的输出)在该词典数组中循环。
1 def buildTestSuiteTree(parent, testSuites, loopDepth):
2 print("[DEBUG] Entering in buildTestSuiteTree")
3 print("[DEBUG] testSuites: {}".format(testSuites))
4 print("[DEBUG] parent id: {}".format(parent.testsuite_id))
5 print("[DEBUG] loopDepth: {}".format(loopDepth))
6 tsChild = TestSuite()
7 index = 0
8 for testSuiteInfo in testSuites:
9 print("[DEBUG] loopDepth: {}".format(loopDepth))
10 testSuiteInfo = decode(str(testSuiteInfo))
11 print("[DEBUG] testSuiteInfo: {}".format(testSuiteInfo))
12 print("[DEBUG] matching against parent id {}".format(parent.testsuite_id))
13 if str(parent.testsuite_id) == testSuiteInfo['parent_id']:
14 print("[DEBUG] FOUND mathing parent!")
15 parent.hasChild = True
16 parent.child = tsChild
17 testSuites.pop(index)
18 tsChild.testsuite_id = int(testSuiteInfo['id'])
19 loopDepth += 1
20 tsChild.child = buildTestSuiteTree(tsChild, testSuites, loopDepth)
21 index += 1
22 return tsChild
我已经知道这不会给我上图(child (id = 282)
)的最后一点,因为我需要为每个孩子使用一些数组,但是目前这不是我的问题:- )
loopDepth
是我试图理解我的问题的尝试。
>>> root = TestSuite()
>>> root.testsuite_id = 213
>>> t = buildTestSuiteTree(root, testSuites,0)
[DEBUG] Entering in buildTestSuiteTree
[DEBUG] testSuites: [{'name': 'Initial release', 'parent_id': '213', 'id': '278'}, {'name': 'Screening', 'parent_id': '279', 'id': '281'}, {'name': 'Web', 'parent_id': '278', 'id': '279'}, {'name': 'Initial release', 'parent_id': '213', 'id': '282'}]
[DEBUG] parent id: 213
[DEBUG] loopDepth: 0
[DEBUG] loopDepth: 0
[DEBUG] testSuiteInfo: {'id': '278', 'parent_id': '213', 'name': 'Initial release'}
[DEBUG] matching against parent id: 213
[DEBUG] FOUND mathing parent!
[DEBUG] Entering in buildTestSuiteTree
[DEBUG] testSuites: [{'name': 'Screening', 'parent_id': '279', 'id': '281'}, {'name': 'Web', 'parent_id': '278', 'id': '279'}, {'name': 'Initial release', 'parent_id': '213', 'id': '282'}]
[DEBUG] parent id: 278
[DEBUG] loopDepth: 1
[DEBUG] loopDepth: 1
[DEBUG] testSuiteInfo: {'id': '281', 'parent_id': '279', 'name': 'Screening'}
[DEBUG] matching against parent id: 278
[DEBUG] loopDepth: 1
[DEBUG] testSuiteInfo: {'id': '279', 'parent_id': '278', 'name': 'Web'}
[DEBUG] matching against parent id: 278
[DEBUG] FOUND mathing parent!
[DEBUG] Entering in buildTestSuiteTree
[DEBUG] testSuites: [{'name': 'Screening', 'parent_id': '279', 'id': '281'}, {'name': 'Initial release', 'parent_id': '213', 'id': '282'}]
[DEBUG] parent id: 279
[DEBUG] loopDepth: 2
[DEBUG] loopDepth: 2
[DEBUG] testSuiteInfo: {'id': '281', 'parent_id': '279', 'name': 'Screening'}
[DEBUG] matching against parent id: 279
[DEBUG] FOUND mathing parent!
[DEBUG] Entering in buildTestSuiteTree
[DEBUG] testSuites: [{'name': 'Initial release', 'parent_id': '213', 'id': '282'}]
[DEBUG] parent id: 281
[DEBUG] loopDepth: 3
[DEBUG] loopDepth: 3
[DEBUG] testSuiteInfo: {'id': '282', 'parent_id': '213', 'name': 'Initial release'}
[DEBUG] matching against parent id: 281
我期望一旦Python到达第13行中没有匹配项的位置,因为它到达了递归循环的最低点,它将回到loopDepth
中的“ up”位置回到“原始”第20行。
从那里,我希望Python继续在原始循环上循环,此时testSuites
:
testSuites: [{'name': 'Initial release', 'parent_id': '213', 'id': '282'}]
然后,用t.child
的最后一个值覆盖testSuites
。
我从输出中看到的只是这些!
我看到Python会以某种方式停留在最低的循环深度,并尝试匹配它找不到的父ID(卡在最后一个孩子身上),然后……好吧,什么都没有。
我知道这可能不是有史以来最干净的代码或pythonesque,也许我可以使用一些树状库来完成这项工作(也许我会讲到这一点),但是我不明白为什么我的程序是表现如预期。
hasChild
都没有设置为yes。我猜这是由于另一个函数调用中的更新上下文所致,但是您可以确认是吗?谢谢大家的关注!
由于Eric的评论,我删除了数组的切片,它确实改善了代码的执行。这是经过修改的代码(我也修改了TestSuite以添加array
属性):
def buildTestSuiteTree(parent, testSuites, loopDepth):
tsChild = TestSuite()
index = 0
for testSuiteInfo in testSuites:
testSuiteInfo = decode(str(testSuiteInfo))
if str(parent.testsuite_id) == testSuiteInfo['parent_id']:
parent.hasChild = True
tsChild.testsuite_id = int(testSuiteInfo['id'])
loopDepth += 1
tsChild.child = buildTestSuiteTree(tsChild, testSuites, loopDepth)
parent.array.append(tsChild)
index += 1
return tsChild
给定初始testSuites
时,它可以很好地创建带有子级数组的第一级对象。
因此,它给出了(这是一个简化的表示):
root (TestSuite, id=213)
.array[ child1 (TestSuite, id=278), child2 (TestSuite, id=282) ]
child1 (TestSuite, id=278)
.array[ child11 (TestSuite, id=279) ]
child11 (TestSuite, id=279)
.array[ child111 (TestSuite, id=281) ]
但是当我给出复杂数据时:
testSuites = [{'id': '278', 'parent_id': '213', 'name': 'Initial release'}, {'id': '281', 'parent_id': '279', 'name': 'Screening'}, {'id': '279', 'parent_id': '278', 'name': 'Web'}, {'id': '282', 'parent_id': '213', 'name': 'Initial release'}]
孩子的第一层是错的:
root (TestSuite, id=213)
.array[ child1 (TestSuite, id=283), child2 (TestSuite, id=283), child3 (TestSuite, id=283) ]
child1 (TestSuite, id=283)
.array[ child11 (TestSuite, id=279) ]
child11 (TestSuite, id=279)
.array[ child111 (TestSuite, id=281) ]
child12 (TestSuite, id=284)
.array[]
child2 (TestSuite, id=283)
.array[ child21 (TestSuite, id=279) ]
child21 (TestSuite, id=279)
.array[ child211 (TestSuite, id=281) ]
child22 (TestSuite, id=284)
.array[]
child3 (TestSuite, id=283)
.array[ child31 (TestSuite, id=279) ]
child31 (TestSuite, id=279)
.array[ child311 (TestSuite, id=281) ]
child32 (TestSuite, id=284)
.array[]
(这不是拼写错误,是相同对象的三倍...)
我还更新了“我愿意实现的目标”,因为我认为我的最终意图并不明确,而Poolka的答案也无法解决(或者至少我无法使其符合我的需求: -))。
答案 0 :(得分:0)
如果我对您的理解正确,'d like to have an object that would go from the root to the last child like this ...
。但是数据存储在列表中,所以您不知道每个父母的所有孩子。因此,您可以在每个递归步骤上遍历testSuites
列表。在循环内,您将处理testSuites
列表的第一个元素,将其从列表中弹出,并使用经过修改的列表testSuites[1:]
进行递归调用。因此,您通过递归实现了循环。不要那样做这很奇怪而且效果很差。
这是我尝试解决问题的方法。 func1()
用于创建所有TestSuite
对象的字典。 func2()
是一种递归函数,用于以您在问题中提供的方式打印TestSuite
对象。
class TestSuite:
def __init__(self, testsuite_id):
self.testsuite_id = testsuite_id
self.hasChild = False
self.childs = set()
def __repr__(self):
str_1 = (
'TestSutie({})'
.format(self.testsuite_id))
str_2 = (
' with childs {}'
.format([child.testsuite_id for child in self.childs])
if self.hasChild
else ' with NO childs')
return str_1 + str_2
def func1(testSuites):
answer = dict()
for suite in testSuites:
if suite['id'] not in answer:
answer[suite['id']] = TestSuite(suite['id'])
if suite['parent_id'] not in answer:
answer[suite['parent_id']] = TestSuite(suite['parent_id'])
answer[suite['parent_id']].hasChild = True
answer[suite['parent_id']].childs.add(answer[suite['id']])
return answer
def func2(root, num=0):
print('| ' * num, end='')
print('id = ', root.testsuite_id)
for child in root.childs:
print('| ' * (num + 1))
func2(child, num + 1)
testSuites = [
{'id': '278', 'parent_id': '213', 'name': 'Initial release'},
{'id': '281', 'parent_id': '279', 'name': 'Screening'},
{'id': '279', 'parent_id': '278', 'name': 'Web'},
{'id': '282', 'parent_id': '213', 'name': 'Initial release'},
{'id': '283', 'parent_id': '213', 'name': 'Initial release'},
{'id': '284', 'parent_id': '283', 'name': 'Screening'}]
answer = func1(testSuites)
print(*answer.values(), sep='\n')
print()
func2(root=answer['213'])
输出:
TestSutie(213) with childs ['283', '278', '282']
TestSutie(278) with childs ['279']
TestSutie(281) with NO childs
TestSutie(279) with childs ['281']
TestSutie(282) with NO childs
TestSutie(283) with childs ['284']
TestSutie(284) with NO childs
id = 213
|
| id = 278
| |
| | id = 279
| | |
| | | id = 281
|
| id = 282
|
| id = 283
| |
| | id = 284