os.path.split

split(p) is (dirname(p), basename(p)) in one call. The cut is at the last separator, so a path ending in / has an empty tail. join(head, tail) gives back an equivalent path.

os.path functionPython 3.0+Live demo
Common call
folder, name = os.path.split(path)
Returns
('/home/ada', 'notes.txt')
Replaces
path.rsplit('/', 1) — which mishandles '/', 'name' and Windows paths
Watch out
'/var/log/' splits into ('/var/log', '') — strip trailing slashes first if you want 'log'
os.path.split(path) → (head, tail)
→ tuple[str, str]

Demo

Live evaluation
POSIX rules via posixpath — the same output on every machine.
Try:
Inputs
pathstra POSIX path
Code
import posixpath
posixpath.split('/home/ada/notes.txt')
Result
('/home/ada', 'notes.txt')

The head loses its trailing slashes, except when it is the root itself: split('/') is ('/', ''). A bare name has an empty head. posixpath treats a backslash as an ordinary character, so a Windows path is one long file name to it; ntpath splits at either slash and keeps 'C:\' together as the head.

Parameters

NameTypeRequiredDescription
pathstr | bytes | PathLikeyesAny path. Nothing is checked on disk.

Return value

tuple[str, str] — (head, tail): tail never contains a separator; head is the rest without trailing separators (unless it is the root).

Common patterns

Folder and name in one call
Tuple unpacking.
import os
folder, name = os.path.split(path)
Last folder name of a directory path
Strip the trailing separator first.
import os
last = os.path.split(path.rstrip(os.sep))[1]
All components
Loop until the head stops changing — or use pathlib: PurePath(p).parts.
import os
def components(p):
    parts = []
    while True:
        head, tail = os.path.split(p)
        if tail:
            parts.insert(0, tail)
        if head == p:
            if head:
                parts.insert(0, head)
            return parts
        p = head

Examples

1. Folder and file
import posixpath posixpath.split('/home/ada/notes.txt')
Returns
('/home/ada', 'notes.txt')
2. Trailing slash: empty tail
import posixpath posixpath.split('/var/log/')
Returns
('/var/log', '')
3. No folder
import posixpath posixpath.split('notes.txt')
Returns
('', 'notes.txt')
4. The root stays the root
import posixpath posixpath.split('/')
Returns
('/', '')
5. join undoes split
import posixpath head, tail = posixpath.split('a/b/c.txt') posixpath.join(head, tail)
Returns
'a/b/c.txt'
6. Windows path with ntpath
import ntpath ntpath.split(r'C:\Users\ada\notes.txt')
Returns
('C:\\Users\\ada', 'notes.txt')
7. The drive root is kept
import ntpath ntpath.split(r'C:\notes.txt')
Returns
('C:\\', 'notes.txt')

Pitfalls

1. Expecting the last folder name from a path with a trailing slash
The tail is what follows the last separator — nothing, here.
split('/var/log/')
import posixpath
posixpath.split('/var/log/')[1]
''
strip first
import posixpath
posixpath.split('/var/log/'.rstrip('/'))[1]
'log'
2. Splitting by hand with rsplit
rsplit('/', 1) returns one item when there is no slash, and turns '/' into two empty strings.
rsplit('/', 1)
('notes.txt'.rsplit('/', 1), '/'.rsplit('/', 1))
(['notes.txt'], ['', ''])
posixpath.split
import posixpath
(posixpath.split('notes.txt'), posixpath.split('/'))
(('', 'notes.txt'), ('/', ''))

When to use

Use it
  • Getting folder and name of a str path together
Reach for something else
  • Only one of the two → dirname / basename
  • All components → PurePath(p).parts
  • Extension → splitext

Notes

CPython impl
posixpath.split: i = p.rfind('/') + 1; head, tail = p[:i], p[i:]; trailing slashes are stripped from head unless it is all slashes. ntpath.split first takes off the drive and root with splitroot
Invariant
join(head, tail) refers to the same location as the original path (it may differ textually, e.g. doubled slashes)

FAQ

folder, name = os.path.split(path). With pathlib: p.parent and p.name.