pythoniterable

Python: Elegent way to get an iterable of all parents in a path


Working with a path-based resource system, the application needs to find the first working resource that manages a given resource based on paths. I need a succinct, pythonic way to generate the following:

Input:

/house/dogs/ralph/bone

Output:

/house/dogs/ralph/bone
/house/dogs/ralph
/house/dogs
/house

Note: It's okay to use os.path or similar built-ins, but these are not filesystem resources. Output can be anything iterable (list, set, generator, etc.).


Solution

  • Use pathlib. PurePaths offer an abstract interface to path-like objects that have no relationship to the file system. In particular, PurePosixPath is the kind that uses forward slashes (/) as separators:

    >>> from pathlib import PurePosixPath
    >>> p = PurePosixPath('/house/dogs/ralph/bone')
    >>> str(p.parent)
    /house/dogs/ralph
    >>> str(p.parent.parent)
    /house/dogs
    

    You can loop this easily:

    p = PurePosixPath(...)
    while str(p) != p.root:
        # Do stuff to p
        p = p.parent
    

    A fairly pythonic finishing touch would be to make it a generator:

    def receding_path(p):
        p = PurePosixPath(p)
        while str(p) != p.root:
            yield str(p)
            p = p.parent
    
    for item in receding_path('/house/dogs/ralph/bone'):
        # do stuff to each item