Экспорт/импорт деревьев, созданных с помощью библиотеки python anytree 2.4.3

Я создаю дерево с библиотекой anytree. Я хочу иметь возможность изменить его, затем экспортировать - сохранить на диск и импортировать обратно с изменениями. Например, пример дерева:

udo = Node("Udo")
marc = Node("Marc", parent=udo)
lian = Node("Lian", parent=marc)
dan = Node("Dan", parent=udo)
jet = Node("Jet", parent=dan)
jan = Node("Jan", parent=dan)
joe = Node("Joe", parent=dan)

Udo
├── Marc
│   └── Lian
└── Dan
    ├── Jet
    ├── Jan
    └── Joe

Я могу изменить его, например, отрезать Дэна и добавить детей к Марку.

dan.parent = None 
bonny = Node ("Bonny", parent = marc)

Udo
└── Marc
    ├── Lian
    └── Bonny

Но когда я экспортирую дерево в json, а затем импортирую его обратно, кажется, что единственный узел, на который я могу сослаться, — это корень. Так что я больше не могу делать такого рода модификации, потому что имена переменных, такие как dan или marc, отсутствуют, т. е. я не нахожу способа сослаться на узел. Я что-то упустил?

with open ('cajon/anytreeexample.json', 'r+', encoding = 'utf-8') as f:
    datos = importer.read(f)

print (datos)

Это означает, что после импорта дерева у вас есть просто корневой узел.

AnyNode(name='Udo')  # Udo is the root

Отсюда вы можете получить детей Удо, а дети детей, как

marc, dan = udo.children
lian = marc.children
jet, jan, joe = dan.children

Но они не работают как узел

print (lian.parent)
AttributeError: 'tuple' object has no attribute 'parent'

И, кажется, вы не можете прикрепить к ним детей, что является моей основной целью с этой структурой:

sonny = AnyNode("Sonny", parent = lian)
TypeError: __init__() got multiple values for argument 'parent'

Итак, мой вопрос: есть ли способ загрузить сохраненное json-дерево в правильную структуру anytree, куда вы можете добавлять новые узлы?


person gaurwraith    schedule 17.08.2018    source источник
comment
Вы можете ссылаться на корень, его дочерние элементы, его дочерние дочерние элементы и т. д.   -  person Stop harming Monica    schedule 18.08.2018
comment
@Goyo Я добавил несколько вопросов, которые возникли после этой идеи. (Я обдумывал это, но не знал, как я пойду, скажем, на узел 5-го уровня, выглядит очень сложно, я действительно не знаю, если это   -  person gaurwraith    schedule 18.08.2018
comment
Но как бы я это сделал без жесткого кодирования? Что ты имеешь в виду? Для того, чтобы привязать переменную нужно присвоить значение variable = value, другого пути нет. Также кажется, что некоторые из них не работают, поскольку узел .children возвращает кортеж, а не узел. И, похоже, я тоже не знаю, как добавлять детей Как насчет sonny = Node("Sonny", parent = dan)?   -  person Stop harming Monica    schedule 18.08.2018
comment
@Goyo, эта последняя строка кода, которую я пробовал раньше, не работает именно потому, что после экспорта вы получаете только кортежи, а не узлы. Также это дерево имеет 6 узлов, но я думаю, что у меня будет 600, первые два уровня исправлены, а затем добавлены по мере того, как я нахожу новые узлы. Должен быть другой способ, чем для каждого узла, создающего его с узлом = узел (имя, родитель = родитель). Вот что я имею в виду под жестким кодированием. Моя идея заключалась в том, что когда я нахожу что-то, что принадлежит ветке, я могу просто использовать функцию, которая говорит добавить этот новый узел в nodeX. Затем сохраните его, и в следующий раз, когда я загружу дерево, там будет новый узел.   -  person gaurwraith    schedule 18.08.2018
comment
.children всегда возвращают кортеж узлов, экспорт тут ни при чем. Чтобы добавить newnode к nodeX, предполагая, что и newnode, и nodeX являются узлами, вы просто делаете newnode.parent = nodeX.   -  person Stop harming Monica    schedule 18.08.2018
comment
@gaurwraith посмотрите ниже, anytree на самом деле ведет себя так, как вы ожидали, вы просто забыли ,   -  person Fabian N.    schedule 18.08.2018


Ответы (1)


Вы действительно сделали это правильно: вы просто забыли ,

from anytree import Node

udo = Node("Udo")
marc = Node("Marc", parent=udo)
Node("Lian", parent=marc)

lian, = marc.children # this is a tupel, even if its only one entry -> add ,
sonny = Node("Sonny", parent = lian)

print (lian.parent)
> Node('/Udo/Marc')

print (sonny)
> Node('/Udo/Marc/Lian/Sonny')

@Как найти свои узлы: вы ищете любые деревья find_by_attr:

Найдите одиночный узел с именем атрибута, имеющим значение [...]

Итак, после загрузки вашего дерева с помощью

with open ('cajon/anytreeexample.json', 'r+', encoding = 'utf-8') as f:
    datos = importer.read(f)

Вы можете искать узлы по имени:

udo = datos.find_by_attr("Udo") # should be the same as datos if udo was the root

А затем добавьте еще вот так:

Node("Sonny", parent = datos.find_by_attr("lian"))
person Fabian N.    schedule 18.08.2018
comment
Да, действительно, корень проблемы был в том, что даже отдельные узлы даны в виде кортежа! - person gaurwraith; 18.08.2018