---
title: "Stop renaming files by hand"
description: "A beginner-friendly Python script that renames messy files in a folder — with a safe dry-run mode so nothing breaks."
url: https://articles.sythra.ai/articles/python-rename-files-script
slug: python-rename-files-script
author: "vaibhavkothari"
author_url: https://articles.sythra.ai/writers/vaibhavkothari
date_published: 2026-07-24T17:46:03.878Z
date_modified: 2026-08-29T10:29:25.265Z
topics: ["Python", "Coding"]
reading_time_minutes: 5
publisher: "Sythra"
publisher_url: https://sythra.ai
access: free
language: en
---

# 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.

Source: https://articles.sythra.ai/articles/python-rename-files-script · Author: vaibhavkothari · Published: 2026-07-24 · Reading time: 5 min · Topics: Python, Coding

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 learning.

This guide uses simple words and small code steps. Copy, run, tweak.

## What you will build

A script that:

1. Looks inside a folder
2. Finds files (for example, all `.jpg` photos)
3. Renames them in a clean pattern: `photo_001.jpg`, `photo_002.jpg`, …
4. First **prints** what it *would* do (safe mode)
5. Only renames for real when you flip a switch

## Before you start

You need Python 3 on your computer. In a terminal, check:

```bash
python --version
```

If that fails, try:

```bash
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 pathlib makes paths easier to read. You import Path from it.

```python
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. iterdir 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 suffix.

```python
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 comprehension. 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 enumerate:

```python
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 padding (`1` → `001`). That keeps order in file explorers. The `f"..."` text is an f-string.

## Step 4 — Dry run (always do this first)

**Dry run** = show the plan, do not change anything yet.

```python
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:

```python
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:

```python
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 __main__ pattern.

Run:

```bash
python rename_files.py
```

```remember
# Remember this
`Path(folder).iterdir()` -> walk a folder without string-joining paths
`p.suffix` / `p.stem` -> extension and name, already split for you
Dry run first -> print the plan before touching anything
---
Anything that renames or deletes gets a dry run as its **default**.
```

## 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](https://app.sythra.ai) — 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.

## Glossary (terms defined in this article)
- **machine learning** (basic) — Teaching computers to find patterns in data so they can make predictions
- **pathlib** (basic) — Python’s modern toolkit for working with file and folder paths
- **Path** (basic) — An object that represents a file or folder location
- **iterdir** (medium) — Lists everything inside a folder
- **suffix** (basic) — The file ending, like .jpg or .pdf
- **list comprehension** (medium) — A short one-line way to build a filtered list
- **enumerate** (basic) — Loop helper that gives both a count and the item
- **format padding** (medium) — Fill with zeros so 1 becomes 001 — keeps names sorting in order
- **f-string** (basic) — A string that can insert variables inside {curly braces}
- **Dry run** (basic) — Preview mode — show what would change without changing it
- **__main__** (medium) — Special name meaning this file was run directly, not imported
