Here, this modified node class only contains object names as strings in node and gives you a set with full "Node" objects when retrieving the "children" or "children", parents "of the node attribute.
There are no cycles inside - therefore, he should avoid the infinity cycle trap. You can implement additional helper methods to facilitate navigation as you see fit.
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
The disadvantage is that it maintains a class dictionary named "all_nodes", where there are links to all the nodes that are actually created. (Pickle is smart enough to only sort this dictionary once for a given graph, since all node objects refer to it). The problem with the "all_nodes" public link is that you need to disassemble and disassemble different sets of graphs. 9 years, let's say you create graphs g1 with a set of nodes, in another run you create a graph g2 with a different set of nodes, and if you decompose g1 and later g2, scattering g2 will override node links for g1). If you need this to work, ask in the comments, and I could come up with something - for the convenience I can come up with, there is a โgraphโ class that will contain a dictionary for all nodes (instead of having it in node class)
source share