Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

For new Python code, use pathlib.Path: Path.exists() checks for any existing filesystem entry, while Path.is_file() and Path.is_dir() require a specific type. The older os.path functions answer the same questions when your code already uses strings. If you are about to read, copy, or delete something, attempting that operation and handling its exception can be safer than performing a separate pre-check.

1. Check for any existing entry with Path.exists()

Use exists() when either a file or a directory is acceptable:

from pathlib import Path

path = Path("config.json")

if path.exists():
    print("The path exists")
else:
    print("Nothing exists at that path")

Path.exists() returns True when the path points to an existing file or directory. It normally follows symbolic links, so a link to an existing target is reported as existing. A missing path and a broken link return False.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

2. Require a regular file with Path.is_file()

Use is_file() when a directory must not satisfy the test:

from pathlib import Path

if Path("config.json").is_file():
    print("config.json is a regular file")
else:
    print("It is missing or is not a regular file")

This predicate is false for directories, missing paths, and broken symbolic links. It normally follows a symbolic link to a regular file. The test says what the path is now; it does not guarantee that the file will remain available for a later operation.

3. Require a directory with Path.is_dir()

Use is_dir() when you need a folder:

from pathlib import Path

folder = Path("data")
if folder.is_dir():
    print("data is a directory")
else:
    print("data is missing or is not a directory")

Files and missing paths return False. Like the other pathlib predicates, this test follows symbolic links by default. A successful directory test does not prove that your process has permission to list or modify the directory.

4. Check a path string with os.path.exists()

os.path is the traditional, string-oriented interface. It also accepts path-like objects and is useful when passing paths to older APIs:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import os

if os.path.exists("config.json"):
    print("The path exists")

Use this when the question is “does any file or directory exist here?” For new code, converting the value to a Path often makes later joins and operations clearer, but there is no need to rewrite stable legacy code solely to change the spelling.

5. Test for a regular file with os.path.isfile()

import os

if os.path.isfile("config.json"):
    print("It is a regular file")
else:
    print("It is not a usable regular file")

os.path.isfile() returns true for an existing regular file and follows symbolic links. It returns false for directories, missing paths, and broken links.

6. Test for a directory with os.path.isdir()

import os

if os.path.isdir("data"):
    print("data is a directory")
else:
    print("data is not an existing directory")

This is the direct os.path equivalent of Path.is_dir(). It is convenient when the rest of an application already stores paths as strings or calls other os.path functions.

7. Discover a match or perform the real operation

Find matching children with glob()

If the real question is whether a directory contains a matching child, test the results of a pattern rather than the directory itself:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
from pathlib import Path

csv_files = Path("data").glob("*.csv")
if any(csv_files):
    print("At least one CSV file exists")
else:
    print("No CSV files were found")

glob() and rglob() yield matching paths. Their results are not guaranteed to be ordered. Recursive patterns such as ** can scan a large tree, so constrain the starting directory and pattern when performance matters.

Inspect children with iterdir()

from pathlib import Path

folder = Path("data")
try:
    for child in folder.iterdir():
        print(child)
except NotADirectoryError:
    print("data is not a directory")
except OSError as exc:
    print(f"Could not read data: {exc}")

iterdir() yields direct children. It raises OSError when the parent is inaccessible or is not a directory, so do not replace this operation with a bare existence check.

Attempt the operation and handle absence

A separate check can become stale between the check and the operation: another process may remove or replace the path. When reading is the goal, combine the attempt with the error handling:

from pathlib import Path

try:
    text = Path("config.json").read_text(encoding="utf-8")
except FileNotFoundError:
    text = ""
except OSError as exc:
    print(f"The file could not be read: {exc}")
    raise

FileNotFoundError specifically describes a required path that is absent. Other OSError subclasses can indicate permissions, a device problem, or another filesystem failure. Catch only the failures you can handle.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Which method should you choose?

Question Recommended API What it distinguishes
Does anything exist at this path? Path.exists() or os.path.exists() File, directory, or another existing entry versus missing
Is this a regular file? Path.is_file() or os.path.isfile() Regular file versus directory or missing path
Is this a directory? Path.is_dir() or os.path.isdir() Directory versus file or missing path
Does a child matching a pattern exist? glob(), rglob(), or iteration Discovery of matching children
Will a read, write, copy, or delete work? Attempt the operation and catch its documented exception The operation’s actual result, including permission and I/O failures

Prefer pathlib for new code because one Path object supports checking, joining, opening, and other filesystem operations. Prefer os.path when an existing interface expects strings or your project consistently uses that API. Neither family is universally faster; choose based on the question and the surrounding code.

Symbolic links, inaccessible paths, and Python versions

  • These predicates normally follow symbolic links and report on the target. A link to a regular file therefore satisfies is_file(); a broken link does not.
  • In newer pathlib versions, Path.exists(follow_symlinks=False) can test the link entry itself rather than following it. Use that form when link identity matters, and verify the Python version running your program supports the parameter.
  • Since Python 3.8, pathlib and os.path predicates return False instead of raising for paths containing characters that cannot be represented by the operating system.
  • A false predicate is not proof that a path is safe to use. Permissions, race conditions, mount failures, and other I/O errors can still affect the operation. Directory iteration and file operations may raise OSError or a more specific exception.

Common mistakes and fixes

Using exists() when a directory is required

A file named data makes Path("data").exists() true. Use is_dir() before treating it as a folder.

Opening a path after a check without handling races

Another process can remove the file after exists() returns. Prefer a try/except FileNotFoundError around the open or read when the operation is the real objective.

Assuming a false result means “permission denied”

Predicates can return false for missing, broken-link, or unrepresentable paths. If you need to diagnose access, perform the operation and inspect the resulting OSError.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Scanning an entire tree unnecessarily

rglob() with a broad recursive pattern can traverse a very large directory. Narrow the root and pattern, or stop after the first match with next():

from pathlib import Path

match = next(Path("data").glob("*.csv"), None)
if match is not None:
    print(match)

Confusing a path relative to the current directory

Relative paths are resolved from the process’s current working directory, which may differ from the script’s directory. Print Path.cwd() while diagnosing an unexpected result, and construct an explicit base path when your application requires one.

Or skip the browser setup

If your Python workflow also needs website screenshots, ScreenshotNeo provides a one-call API rather than a locally managed browser. It removes cookie banners, newsletter popups, and chat widgets before capture; bot checks, blank pages, failed loads, and cache hits are not billed. Its MCP server lets AI agents such as Claude or Cursor call screenshot tools directly. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000 shots.

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

See the ScreenshotNeo API documentation for options such as PNG, JPEG, PDF, full-page capture, selectors, custom JavaScript, waits, headers, cookies, and signed links. Create a free ScreenshotNeo account to get the 1,000 monthly screenshots without a card.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

FAQ

Does Path.exists() check only files?

No. It reports an existing file or directory. Use is_file() or is_dir() when type matters.

Should I use pathlib or os.path?

Use pathlib for new code and os.path when compatibility with string-based code or a legacy interface is the priority.

How can I check whether a folder contains at least one CSV?

Use any(Path(folder).glob("*.csv")), or retrieve the first result with next(..., None) when you do not need every match.

Can a check guarantee that a subsequent open will succeed?

No. The filesystem can change between two statements, and permissions or I/O faults can still prevent the operation. Handle the operation’s exception.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Does Path.exists() check only files?

No. It reports an existing file or directory. Use is_file() or is_dir() when type matters.

Should I use pathlib or os.path?

Use pathlib for new code and os.path when compatibility with string-based code or a legacy interface is the priority.

How can I check whether a folder contains at least one CSV?

Use any(Path(folder).glob("*.csv")), or retrieve the first result with next(..., None) when you do not need every match.

Can a check guarantee that a subsequent open will succeed?

No. The filesystem can change between two statements, and permissions or I/O faults can still prevent the operation. Handle the operation’s exception.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.