Article
Stop renaming files by hand
A beginner-friendly Python script that renames messy files in a folder — with a safe dry-run mode so nothing breaks.

Renaming ten files is annoying. Renaming a hundred is a weekend gone.
You do not need a fancy app for this. A short Python script can rename a whole folder in seconds — and you can practice the same loops and paths you use later in machine learningTeaching computers to find patterns in data so they can make predictions.
This guide uses simple words and small code steps. Copy, run, tweak.
What you will build
A script that:
- Looks inside a folder
- Finds files (for example, all
.jpgphotos) - Renames them in a clean pattern:
photo_001.jpg,photo_002.jpg, … - First prints what it would do (safe mode)
- Only renames for real when you flip a switch
Before you start
You need Python 3 on your computer. In a terminal, check:
python --version
If that fails, try:
python3 --version
Create a practice folder with a few dummy files so you do not touch important photos yet.
Step 1 — Point at a folder
Python’s pathlibPython’s modern toolkit for working with file and folder paths makes paths easier to read. You import PathAn object that represents a file or folder location from it.
from pathlib import Path
folder = Path("my_photos") # change this to your folder name
print(folder.exists())
print(list(folder.iterdir())[:5]) # peek at a few items
What this means: Path("my_photos") is “the folder called my_photos next to my script.” exists() checks it is real. iterdirLists everything inside a folder lists what is inside.
Step 2 — Keep only the files you care about
Folders can hold other folders too. We only want files with a certain ending — the suffixThe file ending, like .jpg or .pdf.
from pathlib import Path
folder = Path("my_photos")
files = [
f for f in folder.iterdir()
if f.is_file() and f.suffix.lower() == ".jpg"
]
print(len(files), "jpg files found")
for f in files[:5]:
print(f.name)
In plain English: “Walk the folder. Keep items that are files and end with .jpg.” That filter uses a list comprehensionA short one-line way to build a filtered list. Change .jpg to .png or .pdf if you need to.
Step 3 — Plan the new names
We number files so they sort nicely: photo_001, photo_002, … using enumerateLoop helper that gives both a count and the item:
for i, old_path in enumerate(files, start=1):
new_name = f"photo_{i:03d}{old_path.suffix.lower()}"
new_path = folder / new_name
print(f"{old_path.name} -> {new_name}")
i:03d is format paddingFill with zeros so 1 becomes 001 — keeps names sorting in order (1 → 001). That keeps order in file explorers. The f"..." text is an f-stringA string that can insert variables inside {curly braces}.
Step 4 — Dry run (always do this first)
Dry runPreview mode — show what would change without changing it = show the plan, do not change anything yet.
from pathlib import Path
DRY_RUN = True # keep True until the printout looks right
folder = Path("my_photos")
files = sorted(
f for f in folder.iterdir()
if f.is_file() and f.suffix.lower() == ".jpg"
)
for i, old_path in enumerate(files, start=1):
new_name = f"photo_{i:03d}{old_path.suffix.lower()}"
new_path = folder / new_name
if new_path.exists() and new_path != old_path:
print("SKIP (name already used):", new_name)
continue
if DRY_RUN:
print(f"[dry-run] {old_path.name} -> {new_name}")
else:
old_path.rename(new_path)
print(f"[renamed] {old_path.name} -> {new_name}")
Run it. Read the lines. If something looks wrong, fix the pattern — your files are still safe.
Step 5 — Rename for real
When the dry-run looks good:
DRY_RUN = False
Run the script again. Watch the [renamed] lines.
Full script (copy-paste)
Save as rename_files.py next to your practice folder:
from pathlib import Path
# --- settings you can change ---
FOLDER = Path("my_photos")
EXTENSION = ".jpg" # e.g. ".png", ".pdf"
PREFIX = "photo" # becomes photo_001.jpg
DRY_RUN = True # set False only when ready
# -------------------------------
def main():
if not FOLDER.exists():
print("Folder not found:", FOLDER)
return
files = sorted(
f for f in FOLDER.iterdir()
if f.is_file() and f.suffix.lower() == EXTENSION.lower()
)
if not files:
print("No matching files.")
return
for i, old_path in enumerate(files, start=1):
new_name = f"{PREFIX}_{i:03d}{old_path.suffix.lower()}"
new_path = FOLDER / new_name
if new_path.exists() and new_path != old_path:
print("SKIP (already exists):", new_name)
continue
if DRY_RUN:
print(f"[dry-run] {old_path.name} -> {new_name}")
else:
old_path.rename(new_path)
print(f"[renamed] {old_path.name} -> {new_name}")
print("Done.", "Dry-run only." if DRY_RUN else "Files updated.")
if __name__ == "__main__":
main()
The if __name__ == "__main__": line means “only run main() when this file is started directly” — a common mainSpecial name meaning this file was run directly, not imported pattern.
Run:
python rename_files.py
Common mistakes (and easy fixes)
| Problem | Fix |
|---|---|
| “Folder not found” | Put the script next to the folder, or use a full path like Path(r"C:\Users\You\Pictures\trip") |
| Nothing renamed | You left DRY_RUN = True — that is intentional until you are ready |
| Wrong files | Change EXTENSION |
| Names collide | The script skips if the new name already exists |
What you just practiced
- Paths with
pathlib - Filtering with a list comprehension
- Loops with
enumerate - A safety switch (
DRY_RUN)
Those same ideas show up in data folders, dataset cleanup, and ML project layouts.
Next step
Want guided practice with runnable labs? Try a Python path on Sythra — same spirit: small steps, real practice, no fluff.
Start with a junk folder. Flip DRY_RUN only when the printout looks right. That habit will save you forever.
