Я думаю, что для вас может быть более полезным, если я опубликую рабочий пример того, как это сделать, вместо того, чтобы разбираться с проблемами, возникающими в коде. Таким образом, мы могли бы достичь понимания намного быстрее. Ваш код имеет правильное представление о том, что он должен отслеживать глубину по мере продвижения. Но единственное, чего не хватает, - это чувства вложенной глубины (дерева). Он знает только предыдущий 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
Разбить это:
Сначала мы принимаем аргумент блока и автоматически преобразуем его локально в список, если вы передали только один элемент блока. Таким образом, вы можете передать либо один блок объектов, либо их список / кортеж.
depth
- наш трекер глубины. Это список целых чисел, которые мы будем наращивать и уменьшать по мере рекурсии. Начинается с 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