0
/ \
1 2
/ \ /|\
3 4 5 6 7
Я пытаюсь вернуть узлы без дочерних элементов (3,4,5,6,7) из объекта с помощью рекурсивной функции.
Он работает с глобальной переменной и этой функцией:
def find(self, nodes):
if not hasattr(self, 'children'):
nodes.append(self)
else:
for i in self.children:
i.find(nodes)
nodes = []
node.find(nodes) # can be any node (0,1,2,3,4, etc.)
print(nodes)
Но я бы хотел использовать return в своей функции. Я пробовал примерно так:
def find2(self):
if not hasattr(self, 'children'):
return self
else:
for i in self.children:
return i.find2()
nodes = root.find2()
print(nodes)
Но у меня получается только 1 узел. Я также пробовал передать массив, как в этом посте: PYTHON Возвращает список из рекурсивной функции. Но я не получаю желаемого результата, потому что древовидная структура (я полагаю) ...
Я застрял, ты можешь мне помочь? Как «вернуть результат каждой итерации рекурсивной функции в переменную»? Спасибо






Обратите внимание, что в вашем базовом случае вы возвращаете один узел. Затем этот узел распространяется обратно в рекурсии и в конечном итоге возвращается. Т.е. узел, который вам возвращается, является первым без дочерних узлов, с которыми вы столкнулись. Есть несколько способов решить эту проблему (например, путем возврата и объединения списков), но я думаю, что естественный способ сделать это - сделать вашу функцию генератором. Для этого просто замените return на yield. Затем возвращаемое значение функции функционирует как итератор, при этом каждая итерация дает следующее значение, которое будет «возвращено» при выполнении, пока функция не завершится.
Вы не предоставили мне достаточно кода, чтобы создать работоспособный и тестируемый пример, но вот мое предположение о том, что вы ищете:
def find(self):
if not hasattr(self, 'children'):
return [self]
nodes = []
for child in self.children:
return nodes.extend(child.find())
return nodes
# ...
nodes = root.find()
print(nodes)
Это пример ввода:
0
/ \
1 2
/ \ /|\
3 4 5 6 7
Подумайте, что вы хотите, чтобы (рекурсивная) функция возвращала для каждого из узлов:
Таким образом, иногда он возвращает один результат, а иногда и несколько. Ошибка в вашем коде здесь, потому что функция заканчивается при первом возврате, она не возвращает много:
for i in self.children:
return i.find2()
Есть два решения:
Итак, вариант 1:
def find(self):
if not hasattr(self, 'children'):
yield self
else:
for child in self.children:
yield from child.find()
вариант 2:
def find(self):
if not hasattr(self, 'children'):
return [self]
else:
rtn = []
for child in self.children:
for result in child.find():
rtn.append(result)
return rtn
Я предпочитаю генератор. Кроме того, мне не особенно нравится тот факт, что некоторые из ваших узлов имеют атрибут children, а другие нет. Я бы удостоверился, что у всех из них есть children, который может быть пустым или непустым. Затем код становится:
def find_leaves(self):
if self.children:
for child in self.children:
yield from child.find_leaves()
else:
yield self
@cdlane for result in child.find() распаковывает список и затем добавляет каждый элемент в rtn. Не тестировал (тестировал только find_leaves), но думаю, должно работать ...
Вы правы, вложенного цикла я не видел. Хотя я думаю, что .extend() имеет больше смысла, чем целый дополнительный цикл!
@cdlane Да, продлить было бы лучше, но я подумал, что это будет легче понять ...
Спасибо за очень хороший ответ. Я не знал ни о
yield(и генераторах), ни о[self]. Сейчас я собираюсь прочитать документацию о них, чтобы понять, как они работают. Ты работает!