Hi,
I am not quite sure what your actual question is. However, I think that you somehow missed the point of writing a node type. The advantage of it is that you can encapsulate any logic into your nodes and can operate on local and small scale. When you write some external functions which operate more or less non-object oriented and on the scale of the whole graph, you could also use a builtin data structure like a dictionary and ignore the whole OO-stuff. I do not want to start a discussion about functional vs. OO programming, use whatever you are comfortable with, but if you want to benefit from some custom node type, you have to implement a custom node type 
Below you will find an example for how I would go about what you are probably trying to do. Please note that this is example code and not by any means something that should be used 
Cheers,
zipit
import os
class BaseNode(object):
"""The base node type.
"""
def __init__(self, **kwargs):
"""The constructor for BaseNode.
Args:
**kwargs: Any non-graph related attributes of the node.
"""
# You might want to encapsulate your attributes in properties, so
# that you can validate / process them, I took the lazy route.
if "name" not in kwargs:
kwargs["name"] = "Node"
self.__dict__.update(kwargs)
self.children = []
self.up = None
self.down = None
self.prev = None
self.next = None
def __iter__(self):
"""Yields all nodes attached to the node.
Yields:
BaseNode: A node attached to this node.
"""
for child in self.children:
yield child
def __repr__(self):
"""The string representation of the node.
"""
msg = "<{} named {} at {}>"
hid = "0x{:0>16X}".format(id(self))
return msg.format(self.__class__.__name__, self.name, hid)
def _link_nodes(self):
"""Builds the links between the children of the instance and the instance.
"""
prev = None
for node in self:
node.up = self
node.prev = prev
if prev is not None:
prev.next = node
prev = node
self.down = self.children[0] if self.children else None
def add(self, nodes):
"""Adds one or multiple nodes to the instance as children.
Args:
nodes (list[BaseNode] or BaseNode): The nodes to add.
Raises:
TypeError: When nodes contains non-BaseNode elements.
"""
nodes = [nodes] if not isinstance(nodes, list) else nodes
# last child of the instance, needed for linked list logic
prev = self.children[-1] if self.children else None
for node in nodes:
if not isinstance(node, BaseNode):
raise TypeError(node)
self.children.append(node)
self._link_nodes()
def pretty_print(self, indent=0):
"""Pretty print the instance and its descendants.
"""
tab = "\t" * indent
a = self.prev.name if self.prev else None
b = self.next.name if self.next else None
c = self.down.name if self.down else None
msg = "{tab}{node} (prev: {prev}, next: {next}, down: {down})"
print(msg.format(tab=tab, node=self, prev=a, next=b, down=c))
for child in self.children:
child.pretty_print(indent+1)
class PathNode(BaseNode):
"""The file-path specialization of a BaseNode.
"""
def __init__(self, path, **kwargs):
"""The constructor of PathNode.
Args:
path (str): The file/folder path of the node.
**kwargs: Any other non-graph related attributes to be attached to the node.
"""
BaseNode.__init__(self, path=path)
self._initialize_path_tree()
def _initialize_path_tree(self):
"""Initializes a path tree with the path attribute of the instance.
Recursively builds a PathNode tree for the folders and files that are descendants of the path attribute of the instance.
"""
# Validate the path attribute.
if not "path" in self.__dict__:
msg = "The node hasn't been initialized with a 'path' attribute."
raise AttributeError(msg)
if not os.path.exists(self.path):
msg = "The path '{path}' does not exist or cannot be accessed."
raise OSError(msg.format(path=self.path))
path = self.path
root_path, element = os.path.split(path)
# Node is a terminal node / file
if os.path.isfile(path):
name, extension = os.path.splitext(element)
self.name = name
self.extension = extension
self.is_file = True
# Node is a non-terminal node / a folder
else:
self.name = element
self.extension = None
self.is_file = False
# Build the children
paths = [os.path.join(path, item) for item in os.listdir(path)]
for item in paths:
self.add(PathNode(path=item))
self.sort()
def get(self, name, inclusive=False):
"""Yields all nodes which have a matching name attribute.
Note:
This your "get_class_node_base_on_its_name" method. I am not quite sure, what you are trying to accomplish with it, so there
are multiple things one could do differently.
Args:
name (str): The name to match against.
Yields:
BaseNode: A node that is a descendant of the instance and which fulfills the criteria.
"""
if self.name == name:
yield self
for item in self:
for result in item.get(name=name):
yield result
def sort(self):
"""Sorts the children by folder/files, file types and names.
"""
if not self.children:
return
key_lambda = lambda x: (x.is_file, x.extension, x.name)
self.children = sorted(self.children, key=key_lambda)
self._link_nodes()
for node in self:
node.sort()
def pretty_print(self, indent=0):
"""Pretty print the directory structure attached to this node.
"""
tab = "\t" * indent
if self.is_file:
msg = "{tab}{name}{ext}".format(tab=tab,
name=self.name,
ext=self.extension)
else:
msg = "{tab}[{name}]".format(tab=tab, name=self.name)
print msg
for child in self.children:
child.pretty_print(indent+1)
def demo():
"""
"""
path = os.path.dirname(__file__)
root = PathNode(path=path)
print "root:", root
root.pretty_print()
print "\nIterate the root node:"
for node in root:
print node
print "\nGet node by name:"
for item in root.get("plots"):
print item
print "\nGet node by name:"
for item in root.get("todo"):
print item
if __name__ == "__main__":
demo()
root: <PathNode named misc at 0x000000000309C0C8>
[misc]
[plots]
plots_interpolation.py
plots_projection.py
plotters.py
[scripts]
svg_colors.py
todo.md
scribbles_1.py
scribbles_2.py
scribbles_3.py
scribbles_4.py
scribbles_5.py
Iterate the root node:
<PathNode named plots at 0x000000000309C208>
<PathNode named scripts at 0x000000000309C548>
<PathNode named todo at 0x000000000309C5C8>
<PathNode named scribbles_1 at 0x000000000309C308>
<PathNode named scribbles_2 at 0x000000000309C448>
<PathNode named scribbles_3 at 0x000000000309C488>
<PathNode named scribbles_4 at 0x000000000309C4C8>
<PathNode named scribbles_5 at 0x000000000309C508>
Get node by name:
<PathNode named plots at 0x000000000309C208>
Get node by name:
<PathNode named todo at 0x000000000309C5C8>
[Finished in 0.1s]