Python
File Handling
Programming
Code Duplication
Best Practices

Pythonic way to check if a file exists?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Checking whether a file exists is easy in Python, but the best approach depends on what you plan to do next. A plain existence check can introduce race conditions if file state changes before use. Pythonic code often prefers trying the operation directly and handling exceptions when failure matters.

Common Existence APIs

Two standard options are pathlib.Path and os.path.

python
1from pathlib import Path
2
3path = Path("data/input.csv")
4print(path.exists())
5print(path.is_file())

exists returns true for files and directories. is_file is safer if you need specifically a regular file.

Equivalent with os.path:

python
1import os
2
3p = "data/input.csv"
4print(os.path.exists(p))
5print(os.path.isfile(p))

Prefer pathlib in new code for clearer object-oriented path handling.

Pythonic Pattern: EAFP

Python style favors EAFP, short for easier to ask forgiveness than permission. Instead of checking first, attempt to open and catch exceptions.

python
1from pathlib import Path
2
3path = Path("data/input.csv")
4
5try:
6    text = path.read_text(encoding="utf-8")
7    print("loaded", len(text), "chars")
8except FileNotFoundError:
9    print("file missing")
10except PermissionError:
11    print("no permission")

This avoids time-of-check and time-of-use race conditions where another process deletes or replaces file after your existence check.

When Existence Check Is Still Useful

Sometimes you only need to display status or choose workflow branch before expensive work. In those cases, explicit existence checks are reasonable.

python
1def classify_path(path: Path) -> str:
2    if not path.exists():
3        return "missing"
4    if path.is_dir():
5        return "directory"
6    if path.is_file():
7        return "file"
8    return "other"

This is clear and useful for UI or diagnostics.

Path.exists returns false for broken symlinks. If symlink awareness matters, use is_symlink and lstat.

python
1from pathlib import Path
2
3p = Path("link-to-data")
4print("exists", p.exists())
5print("is_symlink", p.is_symlink())

In deployment scripts, broken links are a common source of confusion when an existence check appears false but path still exists as link object.

Working with Temporary and User Paths

Normalize and resolve paths early, especially when inputs come from command-line arguments or environment variables.

python
1from pathlib import Path
2
3raw = "~/project/data/input.csv"
4path = Path(raw).expanduser().resolve()
5print(path)

Using normalized paths helps avoid bugs from relative-path assumptions in CI versus local runs.

Utility Helper for Applications

A small helper can centralize behavior and messages.

python
1from pathlib import Path
2from typing import Tuple
3
4
5def ensure_readable_file(path_str: str) -> Tuple[bool, str]:
6    p = Path(path_str).expanduser()
7    if not p.exists():
8        return False, "File does not exist"
9    if not p.is_file():
10        return False, "Path is not a file"
11    if not os.access(p, os.R_OK):
12        return False, "File is not readable"
13    return True, "OK"

Use one helper instead of repeated ad hoc checks across modules.

Testing File Existence Logic

For tests, use tempfile and pathlib to avoid brittle dependency on fixed local paths.

python
1from pathlib import Path
2from tempfile import TemporaryDirectory
3
4with TemporaryDirectory() as tmp:
5    p = Path(tmp) / "x.txt"
6    assert not p.exists()
7    p.write_text("hello")
8    assert p.exists()

This keeps tests isolated and platform-safe.

Cross-Platform Path Notes

Windows and Unix path semantics differ around case sensitivity and separator behavior. When writing portable scripts, normalize with Path and avoid string-based path concatenation. Also treat network-mounted paths as less reliable for strict existence checks because latency and mount state can change between calls.

python
1from pathlib import Path
2base = Path("data")
3child = base / "input.csv"
4print(child)

Using Path composition improves readability and reduces subtle cross-platform bugs.## Common Pitfalls

  • Checking exists and then assuming file state cannot change.
  • Using exists when is_file is required.
  • Ignoring permission errors while checking only presence.
  • Misreading broken symlink behavior.
  • Hardcoding relative paths that differ in CI and production.

Summary

  • Use pathlib for readable modern path handling.
  • Prefer EAFP when you plan to open or read the file.
  • Use explicit existence checks for diagnostics and branching only.
  • Differentiate files, directories, and symlinks intentionally.
  • Write path logic tests with temporary directories for reliability.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.