The os.path.walk routine that ships with the python standard library is limited to traversing the file system tree. A generic traversal for arbitrary (directed) graphs with support for recursion limits and other accumulated partial results seems useful.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | def graphWalker(node, getChildren, toEvaluate, backPack = None):
"""
A generator that (lazily, recursively) applies an operation to a directed graph structure.
@param node the graph node where we start
@param getChildren a callable f such that f(node) returns the child nodes of node
@param toEvaluate a callable g such that the result rr for a node is rr = g(node, backPack)[0]
@param backPack a partial result that is carried along and may change as the graph is traversed.
g(node, backPack)[1] is passed on to the child nodes.
@returns an iterator over the results of applying toEvaluate to every node in the tree
@see walkTest() for an example.
"""
rr = toEvaluate(node, backPack)
yield rr[0]
for child in getChildren(node):
for result in graphWalker(child, getChildren, toEvaluate, rr[1]):
yield result
"""
SAMPLE (TEST) CODE FOLLOWS:
"""
import os
import stat
def walkTest(root = os.getcwd(), recursionLimit = 3):
"""
A walk that prints all the relative path of all files in a file system rooted
at the current directory with respect to that directory. Goes no deeper than
recursionLimit.
"""
def te(node, rl):
root, visitedNodes, name = node[:3]
if rl < 0: raise StopIteration
return (
os.sep.join(visitedNodes + [name])[1:],
rl - 1
)
def absPath(node):
return os.sep.join(
[node[0]] + node[1] + [node[2]]
)
def isdir(path):
"""
@param path the absolute (?) path of the file
"""
return stat.S_ISDIR(os.stat(
path
)[stat.ST_MODE])
def gc(node):
root, visitedNodes, name, depth = node
ab = absPath(node)
if not isdir(ab): return []
return [
(
root,
visitedNodes + [name],
cc,
depth + 1
)
for cc in
os.listdir(ab)]
return graphWalker((root, [], "", 0), gc, te, recursionLimit)
if __name__ == "__main__":
for rr in walkTest():
print rr
|
I have added this algorithm to MISSION ETERNITY's angel-application ( http://angelapp.missioneternity.org ) from where it is available under a BSD license.
Tags: algorithms