Python
Filename Manipulation
Programming
File Extension
Code Tips

How can I replace or strip an extension from a filename in Python?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Filename extension changes are simple in Python if you use path-aware tools instead of manual string slicing. The safest choices are os.path.splitext() and pathlib.Path, because they handle common edge cases such as hidden files, multiple dots, and missing extensions much better than split(".").

Replace One Extension Safely

If you want to replace the final extension, os.path.splitext() is the classic tool. It splits a path into two pieces: the base name and the last suffix.

python
1import os
2
3filename = "report.csv"
4root, ext = os.path.splitext(filename)
5
6print(root)
7print(ext)
8print(root + ".json")

This works well when you want to remove the current suffix and attach a new one. It only removes the final extension, which is exactly what most programs want.

For more modern code, pathlib is usually even clearer:

python
1from pathlib import Path
2
3path = Path("data/report.csv")
4
5print(path.stem)
6print(path.suffix)
7print(path.with_suffix(".json"))

with_suffix() is the cleanest way to replace one suffix while keeping the rest of the path intact.

Strip an Extension Without Replacing It

If you only need the filename without its final extension, the same utilities work:

python
1from pathlib import Path
2
3path = Path("logs/server.log")
4print(path.stem)

Or with os.path:

python
import os

print(os.path.splitext("logs/server.log")[0])

Both return the name without the last suffix. This is much safer than using a hard-coded slice such as name[:-4], which silently breaks when the extension length changes.

Understand Multi-Suffix Filenames

A name like archive.tar.gz has two suffix-like parts. Both splitext() and Path.stem remove only the final part.

python
1from pathlib import Path
2
3path = Path("archive.tar.gz")
4
5print(path.stem)
6print(path.suffix)
7print(path.suffixes)

The result of stem is archive.tar, not archive. That is usually correct. In many workflows, .tar.gz is meaningful as a compound extension, and removing only .gz is the right behavior.

If your application truly wants to strip every suffix, make that rule explicit:

python
1from pathlib import Path
2
3path = Path("archive.tar.gz")
4base = path.name
5
6for suffix in path.suffixes:
7    if base.endswith(suffix):
8        base = base[: -len(suffix)]
9
10print(base)

Do not do this automatically unless the business rule is clear. Multi-suffix files often need special handling.

Hidden Files and No-Extension Names

Path-aware utilities also behave better for Unix-style hidden files. A leading dot does not automatically mean "extension".

python
1from pathlib import Path
2
3print(Path(".bashrc").suffix)
4print(Path("README").suffix)
5print(Path("photo.jpg").suffix)

This is one of the biggest reasons not to use split("."). A filename such as .bashrc is a hidden file with no ordinary suffix, not a blank base name plus an extension.

Rename Files on Disk

If you are changing real files instead of just computing new names, pathlib keeps the code compact.

python
1from pathlib import Path
2
3source = Path("report.txt")
4target = source.with_suffix(".md")
5
6source.rename(target)
7print(target)

That updates the file on disk. If you only need to generate target paths for later use, call with_suffix() without rename().

For batch operations:

python
1from pathlib import Path
2
3for path in Path("input").glob("*.txt"):
4    new_path = path.with_suffix(".md")
5    print(f"{path} -> {new_path}")

This is clear, readable, and avoids manual filename parsing.

Common Pitfalls

  • Using split(".") and breaking filenames with multiple dots.
  • Treating hidden files such as .bashrc as if they had an ordinary extension.
  • Assuming stem removes every suffix instead of only the last one.
  • Replacing extensions with hard-coded string slices.
  • Stripping multiple suffixes without first deciding whether the compound extension is meaningful.

Summary

  • Use os.path.splitext() or pathlib.Path instead of manual string splitting.
  • 'with_suffix() is the cleanest way to replace a single extension.'
  • 'stem and splitext() remove only the last suffix.'
  • Use suffixes only when you intentionally need to reason about compound extensions.
  • Path-aware utilities handle hidden files and no-extension cases correctly.

Course illustration
Course illustration