Welcome, guest | Sign In | My Account | Store | Cart

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.

Python, 81 lines
 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.

Created by Vincent Kraeutler on Mon, 6 Nov 2006 (PSF)
Python recipes (4591)
Vincent Kraeutler's recipes (1)

Required Modules

Other Information and Tasks