os.path.splitext

splitext cuts at the last dot of the last path component: 'archive.tar.gz' gives '.gz', a dot in a folder name is ignored, and a name made only of a leading dot (.bashrc) has no extension. The extension keeps its dot and its case.

os.path functionPython 3.0+Live demo
Common call
root, ext = os.path.splitext(filename)
Returns
('report', '.pdf')
Replaces
filename.split('.')[-1] — wrong for names without a dot and for dotfiles
Watch out
Only the last extension: '.tar.gz' needs a loop (or Path.suffixes)
os.path.splitext(path) → (root, ext)
→ tuple[str, str]

Demo

Live evaluation
Type a file name or path.
Try:
Inputs
pathstra file name or path
Code
import posixpath
posixpath.splitext('reports/2026/summary.pdf')
Result
('reports/2026/summary', '.pdf')

The extension is everything from the last dot of the file name: backup.tar.gz gives '.gz', so replacing it gives site.tar.zip, not site.zip. The leading dot of .bashrc does not count, and the dot in conf.d is in a folder, not in the file name — both give an empty extension. With no extension the new one is simply appended.

Parameters

NameTypeRequiredDescription
pathstr | bytes | PathLikeyesA file name or full path; only its last component is examined.

Return value

tuple[str, str] — (root, ext): ext is '' or starts with '.', and root + ext == path.

Common patterns

Filter by extension, case-insensitively
Compare a lowercased ext against a set.
import os
IMAGES = {'.png', '.jpg', '.jpeg', '.gif'}
images = [n for n in os.listdir(folder) if os.path.splitext(n)[1].lower() in IMAGES]
Output file next to the input
Same folder and stem, new extension.
import os
out_path = os.path.splitext(in_path)[0] + '.json'
All extensions
Peel them off one by one.
import os
def suffixes(name):
    exts = []
    while True:
        name, ext = os.path.splitext(name)
        if not ext:
            return exts
        exts.insert(0, ext)

Examples

1. The last dot wins
import posixpath posixpath.splitext('report.final.pdf')
Returns
('report.final', '.pdf')
2. Dotfiles have no extension
import posixpath posixpath.splitext('.bashrc')
Returns
('.bashrc', '')
3. Dots in folder names are ignored
import posixpath posixpath.splitext('/home/ada.d/README')
Returns
('/home/ada.d/README', '')
4. Compare in lower case
import posixpath posixpath.splitext('photo.JPG')[1].lower()
Returns
'.jpg'
5. Change the extension
import posixpath root, ext = posixpath.splitext('data.csv') root + '.json'
Returns
'data.json'
6. A trailing dot is an extension
import posixpath posixpath.splitext('file.')
Returns
('file', '.')
7. Every extension, with a loop
import posixpath name = 'archive.tar.gz' suffixes = [] while True: name, ext = posixpath.splitext(name) if not ext: break suffixes.insert(0, ext) suffixes
Returns
['.tar', '.gz']

Pitfalls

1. Splitting on '.' yourself
split('.') breaks on dots in folder names and on names without an extension.
split('.')[-1]
[p.split('.')[-1] for p in ['/etc/conf.d/nginx', 'Makefile']]
['d/nginx', 'Makefile']
splitext
import posixpath
[posixpath.splitext(p)[1] for p in ['/etc/conf.d/nginx', 'Makefile']]
['', '']
2. Expecting .tar.gz as one extension
splitext removes only the last one.
one call
import posixpath
posixpath.splitext('backup.tar.gz')[0]
'backup.tar'
split at the first dot of the name
import posixpath
name = posixpath.basename('backup.tar.gz')
name.split('.', 1)[0]
'backup'

When to use

Use it
  • Checking or changing a file extension of a str path
Reach for something else
  • pathlib code → p.suffix, p.suffixes, p.stem, p.with_suffix('.json')
  • Detecting the real file type → mimetypes.guess_type (by name) or reading the file header

Notes

CPython impl
genericpath._splitext: find the last '.', and accept it only if it comes after the last separator and is not part of the run of leading dots of the file name
Invariant
root + ext == path, always
ntpath
Same rule, with \ and / both counting as separators

FAQ

os.path.splitext(path)[1] — it includes the dot ('.pdf'), or is '' when there is none. With pathlib: Path(path).suffix.