Исходный код EJIO.utils.component.tree.general_tree
## /utils/component/tree/general_tree.py
from threading import RLock
from typing import Any
from collections.abc import Iterable, Iterator
from ...struct import TreeNode
__all__ = [
'GeneralTreeNode',
]
[документация]
class GeneralTreeNode(TreeNode):
"""
Узел универсального дерева общего вида (N-арное дерево).
Может содержать неограниченное количество дочерних потомков.
"""
__slots__ = ('_value', '_children', '_lock')
def __init__(self, *args: Any) -> None:
"""
Инициализирует узел дерева.
Примеры:
GeneralTreeNode("Корень") # Одиночный узел
GeneralTreeNode(["Корень", "Child1", "Child2"]) # Из списка/итератора
"""
self._value: Any = None
self._children: list[TreeNode] = []
self._lock: RLock = RLock()
if args:
# Если передан один аргумент и это итерируемая коллекция (не строка)
if len(args) == 1 and isinstance(args[0], Iterable) and not isinstance(args[0], str):
iterator: Iterator[Any] = iter(args[0])
try:
self._value = next(iterator)
for item in iterator:
self.add_child(GeneralTreeNode(item))
except StopIteration:
pass
else:
# Если переданы обычные позиционные элементы
if len(args) == 1:
self._value = args[0]
else:
self._value = args[0]
for item in args[1:]:
self.add_child(GeneralTreeNode(item))
@property
def value(self) -> Any:
"""
Возвращает значение текущего узла.
:return: Значение текущего узла.
"""
with self._lock:
return self._value
@value.setter
def value(self, new_value: Any) -> None:
"""
Устанавливает значение текущего узла.
:param new_value: Новое значение.
"""
with self._lock:
self._value = new_value
@property
def children(self) -> Iterable[TreeNode]:
"""
Возвращает изолированную потокобезопасную копию списка потомков.
:return: Список потомков.
"""
with self._lock:
return list(self._children)
[документация]
def add_child(self, child_node: 'GeneralTreeNode') -> 'GeneralTreeNode':
"""
Потокобезопасно добавляет дочерний узел в дерево.
:param child_node: Новый дочерний узел.
:return: Новый узел.
"""
with self._lock:
if child_node not in self._children:
self._children.append(child_node)
return child_node
[документация]
def remove_child(self, child_node: 'GeneralTreeNode') -> None:
"""
Потокобезопасно удаляет дочерний узел из дерева.
:param child_node: Дочерний узел.
"""
with self._lock:
if child_node in self._children:
self._children.remove(child_node)
[документация]
def destroy(self) -> None:
"""Потокобезопасное каскадное уничтожение N-арного дерева."""
with self._lock:
# 1. Рекурсивно запускаем уничтожение для всех дочерних узлов
for child in self._children:
if child is not None:
child.destroy()
# 2. Полностью очищаем ссылки на детей текущего узла
self._children.clear()
# 3. Обнуляем полезную нагрузку (важно, если там лежали тяжелые объекты или виджеты)
self._value = None
# Зануляем ссылку на замок, завершая деструкцию
self._lock = None # type: ignore[assignment]
def __repr__(self) -> str:
"""
Строковое представление узла.
:return: Представление узла в виде строки.
"""
with self._lock:
return f"GeneralTreeNode({self._value!r}, children_count={len(self._children)})"