ShopperCove
Menu
All writingBlogTopicsCategoriesAboutRSS
Blog
Categories
Observability & SRE62All categories
About

Plate 95

  1. Blog

Path.glob vs listdir+fnmatch: Localhost Lab

Hands-on Path.glob vs os.listdir+fnmatch.filter one-dir lab: real matches/s on *.py files, measured on Linux localhost today in this hands-on lab for SREs.

Aditya Challa·1 October 2026·4 min read

Lab
On this page
  1. Intro — what this post promises
  2. Arms
  3. Lab topology
  4. Lead table — medium (p50 matches/s)
  5. Scale sketch (Path.glob vs listdir+fnmatch)
  6. Glob pattern cost
  7. Reading it
  8. When Path.glob is still right
  9. endswith vs fnmatch
  10. Object tax
  11. Pitfalls
  12. Reproduce
  13. Limits
  14. Takeaway

Intro — what this post promises

Match files in one directory: Path.glob('*.py') vs os.listdir + fnmatch.filter. This lab reports matches/s on Linux localhost.

It is not glob-vs-rglob-vs-walk (lab 76) and not fnmatch-vs-re pattern microbenches (lab 93). Focus: Path.glob vs listdir+fnmatch on a single directory.

Related links:

  • glob vs rglob vs walk localhost lab
  • fnmatch vs re localhost lab
  • tomllib vs json localhost lab
  • stat vs path stat localhost lab
  • heapq merge vs sorted localhost lab
  • islice vs list slice localhost lab
  • dataclass replace vs manual localhost lab
  • mmap write vs write localhost lab

Lab honesty (1 Oct 2026 IST): Python 3.13.5. Affiliates: 0. Flat dirs only.

Verdict up front (medium 2000 entries / 400 *.py): listdir+endswith ~721109 matches/s; listdir+fnmatch ~526570; Path.glob ~294091; Path.iterdir+suffix ~61488.


Arms

ArmPattern
Path.glob('*.py')pathlib
listdir + fnmatch.filterclassic
listdir + endswith('.py')fixed suffix fast path
scandir + endswithDirEntry
Path.iterdir + .suffixpathlib scan

Lab topology

small 200/40 · medium 2000/400 · large 8000/1600 · 7 rounds · p50
metric: matches/s = n_match / p50_s

Script: lab-evidence/113-path-glob-vs-fnmatch/results/run_lab.py.


Lead table — medium (p50 matches/s)

Armmatches/sentries/s
listdir + endswith7211093605546
scandir + endswith6229373114687
listdir + fnmatch5265702632850
Path.glob2940911470453
Path.iterdir + suffix61488307440

Scale sketch (Path.glob vs listdir+fnmatch)

SizePath.globlistdir+fnmatch
small295655485484
medium294091526570
large287243554569

Glob pattern cost

*.py is a cheap filter. Patterns with multiple * / ? classes push more work into fnmatch — still usually dominated by directory listing syscall cost on large folders. Re-measure if your matcher is ** recursive (again: lab 76).


Reading it

  • Simple *.ext on one dir → listdir/scandir + endswith leads here.
  • Need glob wildcards beyond a suffix → fnmatch or Path.glob.
  • Path.glob stays convenient and mid-pack; fine for tooling scripts.
  • Recursive trees → lab 76 (rglob / walk), not this post.

When Path.glob is still right

Tooling scripts that already speak pathlib, need brace-free relative patterns, or may later grow a single * directory segment often stay on Path.glob for clarity. The ~2× gap vs listdir+fnmatch on medium here rarely matters unless you scan directories in a tight loop.


endswith vs fnmatch

endswith(".py") is not a glob. It misses patterns like test_*.py or *.pyc exclusions. Use it only for fixed-suffix filters; otherwise fnmatch.filter / Path.glob keep semantics honest. Lab 93 covers pattern-engine speed in isolation — not directory IO.


Object tax

Path.iterdir() yielding Path objects paid a clear tax versus name-only listdir/scandir arms. If you only need filenames for a filter, keep strings until you must touch the filesystem again.


Pitfalls

  • Using Path.iterdir lists when you only need names (Path object tax showed up here).
  • Running rglob accidentally when one directory was intended.
  • Treating fnmatch pattern speed (lab 93) as directory listing speed.
  • Ignoring locale/case rules on case-insensitive filesystems.

Reproduce

python3 lab-evidence/113-path-glob-vs-fnmatch/results/run_lab.py

Evidence: summary.json, summary.txt, tree/.

For CI file collectors, scandir+endswith on a fixed suffix is a good default; graduate to fnmatch/Path.glob when patterns get expressive.

Always verify match counts against a known fixture before trusting a faster filter in production sweeps.


Limits

One Linux box. Flat synthetic directories. Pattern fixed to *.py. Not networked FS.


Takeaway

At 2000 entries, listdir+fnmatch ~526570 matches/s beat Path.glob ~294091; plain endswith ~721109 led for suffix-only filters. Use Path.glob for ergonomics; listdir+fnmatch/endswith when directory scans are hot.

path.globfnmatch.filteros.listdirpathlibdirectory globlocalhost labsrematches/s

Lab evidence

What I found running this

Lab 1 Oct 2026 IST. Python 3.13.5. medium 2000/400: listdir_fnmatch 526570 matches/s; Path.glob 294091; endswith 721109. One dir only — not lab 76/93. Affiliates: 0. Evidence: lab-evidence/113-path-glob-vs-fnmatch/.

Notes when a lab post goes up

Occasional email for new hands-on reviews. No sequence and no sponsors.

Related links

  • Plate 58

    os.stat vs Path.stat vs lstat: Localhost Lab

    Hands-on os.stat vs pathlib.Path.stat vs os.lstat: real metadata stats/s on many regular files, measured on Linux localhost in this hands-on lab for SREs.

    Observability & SRE · 30 Sept 2026

  • Plate 18

    fnmatch vs re Name Filter: Localhost Lab

    Hands-on fnmatch.filter vs re.compile name-list filtering measured on Linux localhost.

    Observability & SRE · 30 Sept 2026

  • Plate 85

    scandir vs listdir vs iterdir: Localhost Lab

    Hands-on os.scandir vs listdir vs Path.iterdir lab: real entries/s for names and is_file on a synthetic tree, measured on Linux localhost (lab) for SREs.

    Observability & SRE · 30 Sept 2026

On this page

  1. Intro — what this post promises
  2. Arms
  3. Lab topology
  4. Lead table — medium (p50 matches/s)
  5. Scale sketch (Path.glob vs listdir+fnmatch)
  6. Glob pattern cost
  7. Reading it
  8. When Path.glob is still right
  9. endswith vs fnmatch
  10. Object tax
  11. Pitfalls
  12. Reproduce
  13. Limits
  14. Takeaway
All writingBlogCategoriesTopicsAboutPrivacyRSS

© 2026 ShopperCove