4

I would like to write a Python function that is capable of taking a file path, like:

/abs/path/to/my/file/file.txt

And returning three string variables:

  • /abs - the root directory, plus the "top-most" directory in the path
  • file - the "bottom-most" directory in the path; the parent of file.txt
  • path/to/my - everything in between the top- and bottom-most directories in the path

So something with the following pseudo-code:

def extract_path_segments(file):
    absPath = get_abs_path(file)
    top = substring(absPath, 0, str_post(absPath, "/", FIRST))
    bottom = substring(absPath, 0, str_post(absPath, "/", LAST))
    middle = str_diff(absPath, top, bottom)

    return (top, middle, bottom)

Thanks in advance for any help here!

4 Answers 4

5

You are looking for os.sep, together with various os.path module functions. Simply split the path by that character, then re-assemble the parts you want to use. Something like:

import os

def extract_path_segments(path, sep=os.sep):
    path, filename = os.path.split(os.path.abspath(path))
    bottom, rest = path[1:].split(sep, 1)
    bottom = sep + bottom
    middle, top = os.path.split(rest)
    return (bottom, middle, top)

This does not deal very well with Windows paths, where both \ and / are legal path separators. In that case you also have a drive letter, so you'd have to special-case that as well anyway.

Output:

>>> extract_path_segments('/abs/path/to/my/file/file.txt')
('/abs', 'path/to/my', 'file')
Sign up to request clarification or add additional context in comments.

7 Comments

Can't "\" or "/" be used as a path separator on windows? I don't think that this will work in that case ... (although, I'm willing to not work on windows ;-)
@mgilson: Yes, windows accepts both, but os.sep is always \`. That's a pain, so I've defined sep` as a keyword argument that defaults to os.sep.
Quoth the os.sep docs: "Note that knowing this is not sufficient to be able to parse or concatenate pathnames — use os.path.split() and os.path.join() — but it is occasionally useful."
@lazyr: Lucky for me, on windows you'd also have to content with the drive letter at the start, which the OP didn't specify how to deal with, so I'll just ignore the Windows case. :-)
fails when path has less than 3 '/'
|
3

use os.path.split:

import os.path

def split_path(path):
    """
    Returns a 2-tuple of the form `root, list_of_path_parts`
    """
    head,tail = os.path.split(path)
    out = []
    while tail:
        out.append(tail)
        head,tail = os.path.split(head)
    return head,list(reversed(out))

def get_parts(path):
    root,path_parts = split_path(path)
    head = os.path.join(root,path_parts[0])
    path_to = os.path.join(*path_parts[1:-2])
    parentdir = path_parts[-2]
    return head,path_to,parentdir

head,path_to,parentdir = get_parts('/foo/path/to/bar/baz')
print (head)        #foo
print (path_to)     #path/to
print (parentdir)   #bar

1 Comment

Conforms with recommmendations in docs? Check. Cross-platform? Check. This is the way to do it. It should be noted that get_parts requires absolute and normalized paths as argument (e.g. /abs/path/to/my/file/subdir/../file.txt will fail) and that it does not handle windows network mount points (\\server\share\abs\path\to\my\file\file.txt), but those problems are easily amended.
2
>>> p = '/abs/path/to/my/file/file.txt'
>>> r = p.split('/')
>>> r[1],'/'.join(r[2:-2]),r[-2]
('abs', 'path/to/my', 'file')

Comments

2

Using os.path.split() and os.path.join() as we are supposed to

>>> import os
>>> pth = "/abs/path/to/my/file/file.txt"
>>> parts = []
>>> while True:
...     pth, last = os.path.split(pth)
...     if not last:
...         break
...     parts.append(last)
...
>>> pth + parts[-1]
'/abs'
>>> parts[1]
'file'
>>> os.path.join(*parts[-2:1:-1])
'path/to/my'

As a function

import os

def extract_path_segments(pth):
    parts = []
    while True:
        pth, last = os.path.split(pth)
        if not last:
            break
        parts.append(last)
    return pth + parts[-1], parts[1], os.path.join(*parts[-2:1:-1])

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.