Здесь этот модифицированный класс узла содержит только имена объектов в виде строк в узле и предоставляет вам набор с полными объектами "Узел" при извлечении атрибута "children" или "parent" узла .
Внутри нет циклов - поэтому следует избегать ловушек бесконечного цикла. Вы можете реализовать дополнительные вспомогательные методы для упрощения навигации по своему усмотрению.
class Node(object):
all_nodes = {}
def __new__(cls, name):
self = object.__new__(cls)
cls.all_nodes[name] = self
return self
def __getstate__(self):
self.all_nodes = self.__class__.all_nodes
return self.__dict__
def __setstate__(self, dct):
self.__class__.all_nodes = dct["all_nodes"]
del dct["all_nodes"]
self.__dict__ = dct
def __init__(self, name):
#self.all_nodes = self.__class__.all_nodes
self.name = name
self.uid = 0
self._parents = set()
self._children = set()
def __hash__(self):
return hash(self.name)
def __eq__(self, that):
return self.name == that.name
def __repr__(self):
return "\n" + "\n".join(["Name: " + self.name,
"\tChildren:" + ", ".join([c.name for c in self.children]),
"\tParents:" + ", ".join([p.name for p in self.parents])
]
)
def get_relations(self, which):
names = getattr(self, which)
return set(self.__class__.all_nodes[name] for name in names)
@property
def children(self):
return self.get_relations("_children")
@property
def parents(self):
return self.get_relations("_parents")
def __contains__(self, item):
return item.name in self._children
def add(self, child):
self._children.add(child.name)
child._parents.add(self.name)
connect_child = add
#example and testing:
from cPickle import loads, dumps
n1 = Node("n1")
n2 = Node("n2")
n3 = Node("n3")
n1.add(n2)
n2.add(n3)
n3.add(n1)
print n1, n2, n3
p1 = dumps(n1)
Node.all_nodes.clear()
p2 = loads(p1)
print p2
print p2.children
print p2.children.pop().children
print Node.all_nodes
Недостатком является то, что он поддерживает словарь классов с именем "all_nodes", в котором есть ссылки на все фактически созданные узлы. (Pickle достаточно умен, чтобы выбрать этот словарь только один раз для данного графа, поскольку на него ссылаются все объекты Node).
Проблема со ссылкой на весь класс "all_nodes" заключается в том, что вам нужно выбирать и снимать различные наборы графов. 9let скажем, что вы создаете графы g1 с набором узлов, в другом прогоне создаете граф g2 с другим набором узлов и затем, если вы откроете g1, а затем g2, удаление g2 переопределит ссылки на узлы для g1). Если вам нужно, чтобы это работало, спросите в комментарии, и я мог бы что-то придумать - проще всего подумать о том, чтобы иметь класс «graph», который будет содержать словарь для всех узлов (вместо того, чтобы иметь его в классе Node )