Python
Subdirectories
File System
Coding
Programming

How to get all of the immediate subdirectories in Python

Interview Questions practice on Codemia

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

Browse interview questions

Introduction

To get all immediate subdirectories in Python, use pathlib.Path.iterdir() with an is_dir() filter (recommended) or os.listdir() combined with os.path.isdir(). The pathlib approach is the most readable: [p for p in Path(directory).iterdir() if p.is_dir()]. For the os module: [d for d in os.listdir(directory) if os.path.isdir(os.path.join(directory, d))]. Both return only direct children — not nested subdirectories.

python
1from pathlib import Path
2
3# Get all immediate subdirectories
4directory = Path('/home/user/project')
5subdirs = [p for p in directory.iterdir() if p.is_dir()]
6
7# Just the names
8subdir_names = [p.name for p in directory.iterdir() if p.is_dir()]
9print(subdir_names)
10# ['src', 'tests', 'docs', '.git']
11
12# Exclude hidden directories
13visible_subdirs = [p for p in directory.iterdir() if p.is_dir() and not p.name.startswith('.')]
14print(visible_subdirs)
15# [PosixPath('/home/user/project/src'), PosixPath('/home/user/project/tests'), ...]
16
17# Sorted alphabetically
18sorted_subdirs = sorted(directory.iterdir(), key=lambda p: p.name)
19subdirs_only = [p for p in sorted_subdirs if p.is_dir()]

os Module Approach

python
1import os
2
3directory = '/home/user/project'
4
5# Get immediate subdirectories
6subdirs = [d for d in os.listdir(directory)
7           if os.path.isdir(os.path.join(directory, d))]
8print(subdirs)
9# ['src', 'tests', 'docs', '.git']
10
11# Full paths
12subdir_paths = [os.path.join(directory, d) for d in os.listdir(directory)
13                if os.path.isdir(os.path.join(directory, d))]

os.scandir — Faster for Large Directories

os.scandir() is significantly faster than os.listdir() because it reads directory entries without extra stat() calls:

python
1import os
2
3directory = '/home/user/project'
4
5# os.scandir returns DirEntry objects with cached is_dir()
6subdirs = [entry.name for entry in os.scandir(directory) if entry.is_dir()]
7print(subdirs)
8# ['src', 'tests', 'docs']
9
10# Full paths
11subdir_paths = [entry.path for entry in os.scandir(directory) if entry.is_dir()]
12
13# With context manager (recommended for resource cleanup)
14with os.scandir(directory) as entries:
15    subdirs = [entry.name for entry in entries if entry.is_dir()]

os.walk — Limited to First Level

os.walk() is designed for recursive traversal, but you can take only the first result:

python
1import os
2
3directory = '/home/user/project'
4
5# next() gets only the first level (root directory)
6_, subdirs, _ = next(os.walk(directory))
7print(subdirs)
8# ['src', 'tests', 'docs']

This is concise but less obvious than the iterdir or scandir approaches.

glob Pattern Matching

python
1import glob
2from pathlib import Path
3
4directory = '/home/user/project'
5
6# glob with trailing slash matches directories
7subdirs = glob.glob(os.path.join(directory, '*/'))
8# ['/home/user/project/src/', '/home/user/project/tests/', ...]
9
10# pathlib glob — matches only immediate children with *
11subdirs = [p for p in Path(directory).glob('*') if p.is_dir()]

Filtering Subdirectories

python
1from pathlib import Path
2
3project = Path('/home/user/project')
4
5# Exclude hidden directories and __pycache__
6subdirs = [
7    p for p in project.iterdir()
8    if p.is_dir() and not p.name.startswith('.') and p.name != '__pycache__'
9]
10
11# Only directories matching a pattern
12test_dirs = [p for p in project.iterdir() if p.is_dir() and p.name.startswith('test')]
13
14# Directories containing a specific file
15packages = [
16    p for p in project.iterdir()
17    if p.is_dir() and (p / '__init__.py').exists()
18]
19print(packages)
20# Directories that are Python packages

Performance Comparison

python
1import os
2from pathlib import Path
3import timeit
4
5directory = '/usr/lib'  # A large directory for benchmarking
6
7# os.scandir — fastest (no extra stat calls)
8def with_scandir():
9    return [e.name for e in os.scandir(directory) if e.is_dir()]
10
11# pathlib.iterdir — clean API, slightly slower
12def with_pathlib():
13    return [p.name for p in Path(directory).iterdir() if p.is_dir()]
14
15# os.listdir + isdir — slowest (calls stat per entry)
16def with_listdir():
17    return [d for d in os.listdir(directory)
18            if os.path.isdir(os.path.join(directory, d))]
19
20# Typical results on a directory with ~500 entries:
21# scandir:  ~0.8 ms
22# pathlib:  ~1.2 ms
23# listdir:  ~2.5 ms

For most applications the difference is negligible, but os.scandir() wins on directories with thousands of entries.

Common Pitfalls

  • os.listdir returns names, not paths: It returns ['src', 'tests'], not full paths. You must join with the parent directory using os.path.join(directory, name) before calling os.path.isdir(). Passing just the name to isdir() checks relative to the current working directory, which gives wrong results.
  • Symlinks to directories: is_dir() and os.path.isdir() follow symlinks by default — a symlink pointing to a directory counts as a directory. To exclude symlinks, add and not p.is_symlink() (pathlib) or and not os.path.islink(path) (os module).
  • Permission errors on subdirectories: iterdir() and scandir() can raise PermissionError if you lack read permission on the parent directory. Wrap in try/except or check os.access(directory, os.R_OK) before iterating.
  • Forgetting hidden directories: .git, .venv, and .cache are valid directories that appear in results. If you want only visible directories, explicitly filter out names starting with ..
  • Using os.walk when you only need one level: os.walk() traverses the entire directory tree. Using next(os.walk(directory)) stops after the first level but still initializes the full generator. Use iterdir() or scandir() instead for single-level listing.

Summary

  • Use [p for p in Path(dir).iterdir() if p.is_dir()] for clean, readable code (recommended)
  • Use os.scandir() for best performance on large directories
  • Use next(os.walk(dir)) as a quick shortcut but prefer iterdir or scandir for clarity
  • Always join directory names with the parent path before calling os.path.isdir()
  • Filter out hidden directories (.name.startswith('.')) and __pycache__ when needed

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.