Обходить граф и возвращать экземпляры класса, созданные рекурсивным вызовом узла с дочерними элементами для аргументов

#python #recursion #directed-acyclic-graphs

#python #рекурсия #directed-acyclic-graphs

Вопрос:

Есть график, отображающий типы классов в список их аргументов. Как мне вернуть корни, созданные с их предками для аргументов? (Извиняюсь за то, что, вероятно, является ужасным описанием моей проблемы). Рассмотрим следующее:

 graph = {Foo: [42], Baz: [None], Bar: [Baz], FooBar: [Foo, Bar], Qux: [True]}
 

Для корней, возвращаемых set(graph).difference(chain.from_iterable(graph.values())) , я ожидаю два значения, qux и foobar , созданные следующим образом:

 qux = Qux(True)
foobar = FooBar(Foo(42), Bar(Baz(None)))
 

Вот дополнительный код для воспроизведения примера:

 from itertools import chain


class Node:
    name = None
    def __init__(self, *args):
        self.args = args


class FooBar(Node):
    name = 'foobar'


class Foo(Node):
    name = 'foo'
    parent = FooBar


class Bar(Node):
    name = 'bar'
    parent = FooBar


class Baz(Node):
    name = 'baz'
    parent = Bar


class Qux(Node):
    name = 'qux'
 

Заранее благодарю.

Комментарии:

1. Вы хотите создать отдельный класс для каждого экземпляра? Это не то, для чего нужны классы!

2. Это имеет место в этом упрощенном примере.

3. Я предлагаю изменить ваш код, чтобы создать другой объект того же класса для каждого экземпляра. Не создавайте отдельный класс для каждого узла вашего графика.

4. Спасибо, хотя в реальном приложении эти классы имитируют широко используются / повторно используются. Опять же, это упрощенный пример.

Ответ №1:

Вы могли бы использовать эту рекурсивную функцию:

 def get_inst (graph, arg):
    val = graph[arg]
    
    return arg(*(el if type(el) != type else get_inst (graph, el) for el in val))
 

Пример использования этой функции:

 roots = set(graph).difference(chain.from_iterable(graph.values()))

for root in roots:
    val = get_inst(graph, root)
 

Комментарии:

1. Отличное решение. Спасибо.