Python通过对象和子对象递归,打印子深度号

2024-03-28 08:24:07 发布

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

我有一个简单的类,它的属性可以包含同一类的对象列表

class BoxItem:
  def __init__(self, name, **kw):
      self.name = name
      self.boxItems = []
      ... #more attributes here

box1 = BoxItem('Normal Box')
box2 = BoxItem('Friendly Box')
box3 = BoxItem('Cool Box')
box4 = BoxItem('Big Box', [box1, box2]) #contains some children
example = BoxItem('Example Box', [box4,box3]) #contains another level of children

使用我们的“example”box对象,我想在它可能拥有的所有可能的box子对象的深度中移动,并打印出如下格式的对象:

1 Example Box
 1.1 Big Box
  1.1.1 Normal Box
  1.1.2 Friendly Box
 1.2 Cool Box

不需要中间的制表符,只想清楚地显示树格式。我可以自己浏览对象并打印出它们的标题,但无法打印出显示父/子关系的前几个数字。(1,1.1,1.2…)

提前感谢您的帮助:)

编辑 这是我到目前为止一直在做的事情

def print_boxes(box_list):
  node_count = 0
  for box in box_list:
    node_count += 1
    print str(node_count)+' '+box.name #prints out the root box
    recursive_search(box,node_count)

 def recursive_search(box,node_count): #recursive automatically 
  level = 0
  for child in box.boxItems:
    level += 1
    for x in range(len(child.boxItems)):
      print x+1 #this prints out some proper numbers
    print "level: "+str(level) #experiment with level
    print child.name #prints out child box name
    recursive_search(child,node_count) #runs the function again  inside the function

Tags: 对象nameselfboxnodechildfordef
2条回答

我认为,如果我发布一个关于如何做到这一点的工作示例,而不是查看您的代码遇到问题的地方,可能会对您更有帮助。这样我们可能会更快地理解。你的代码有一个正确的想法,那就是它需要在运行时跟踪深度。但它唯一缺少的是嵌套深度(树)的感觉。它只知道前一个node_count,然后知道当前的子计数。

我的示例使用闭包启动深度跟踪对象,然后创建一个内部函数来执行递归部分。

def recurse(box):

    boxes = not isinstance(box, (list, tuple)) and [box] or box

    depth = [1]

    def wrapped(box):

        depthStr = '.'.join([str(i) for i in depth])
        print "%s %s" % (depthStr, box.name)

        depth.append(1)
        for child in box.boxItems:
            wrapped(child)
            depth[-1] += 1
        depth.pop()

    for box in boxes:
        wrapped(box)
        depth[0] += 1

示例输出示例:

>>> recurse(example)
1 Example Box
1.1 Big Box
1.1.1 Normal Box
1.1.2 Friendly Box
1.2 Cool Box

>>> recurse([example, example])
1 Example Box
1.1 Big Box
1.1.1 Normal Box
1.1.2 Friendly Box
1.2 Cool Box
2 Example Box
2.1 Big Box
2.1.1 Normal Box
2.1.2 Friendly Box
2.2 Cool Box

分解:

我们首先接受一个box参数,如果只传入了一个box项,则会自动将其本地转换为列表。这样就可以传递一个box对象,或者传递一个列表/元组。

depth是我们的深度跟踪器。它是一个int列表,当递归发生时,我们将建立并缩小它。第一项/第一级从1开始。随着时间的推移,它可能看起来像这样:[1,1,2,3,1]这取决于它穿越的深度。这是我的代码与您的代码之间的主要区别。每个递归都可以访问此状态。

现在我们有了这个内在的wrapped功能。它将获取一个当前的box项并打印它,然后遍历它的子项。我们通过加入当前深度列表和名称来获取打印字符串。

每次我们进入子列表时,我们都会在深度列表中添加一个起始级别1,当我们从子循环中出来时,我们会再次弹出它。对于该循环中的每个子项,我们将最后一项递增。

在这个wrapped内部函数之外,我们通过循环初始框开始整个过程,调用wrapped,然后递增第一个级别。

内部包装函数在闭包中使用深度列表。我敢打赌,其他人可以在这方面提供一些进一步的改进,但这是我想出的一个例子。

注意函数的参数

我们还可以设计recurse来代替使用可变长度的参数列表,而不是检查列表。它看起来是这样的(并且会去掉第一个boxes =检查):

def recurse(*boxes):
    #boxes will always come in as a tuple no matter what

>>> recurse(example)
>>> recurse(example, example, example)

如果最初是以框项目列表开始,则可以通过执行以下操作传递:

>>> boxes = [example, example, example]
>>> recurse(*example)    # this will unpack your list into args

你有两个选择:

  1. 在递归中作为附加参数跟踪附加信息,例如myRecursiveFunction(..., ancestry=[])
  2. 每当BoxItem嵌入BoxItem(在__init__构造函数中,为每个子项设置child.parent = self)时,让每个BoxItem跟踪其父项。如果你打算在多个盒子里放一个盒子里的东西,那就不好了。

相关问题 更多 >