A Comprehensive Guide to Getting All Subdirectories in Python

Oct 21, 2025 · Programming · 23 views · 7.8

Keywords: Python | Directory Operations | Subdirectory Retrieval | Filesystem | Performance Optimization

Abstract: This article provides an in-depth exploration of various methods to retrieve all subdirectories under the current directory in Python, including the use of os.walk, os.scandir, glob.glob, and other modules. It analyzes the applicable scenarios, performance differences, and implementation details of each approach, offering complete code examples and performance comparison data to help developers choose the most suitable solution based on specific requirements.

Introduction

In filesystem operations, retrieving a list of subdirectories under a directory is a common requirement. Python offers multiple approaches to accomplish this task, each with specific advantages and applicable scenarios. This article systematically introduces various methods for obtaining subdirectories and provides code examples and performance analysis to help readers gain a deep understanding.

Using os.walk for Recursive Subdirectory Retrieval

os.walk is a core function in Python's standard library for traversing directory trees. It recursively traverses the specified directory and all its subdirectories using a generator approach, returning tuples containing directory paths, subdirectory lists, and file lists.

import os

# Get all subdirectories under current directory (recursive)
all_subdirectories = [x[0] for x in os.walk('.')]
print(f"Found {len(all_subdirectories)} subdirectories")
for directory in all_subdirectories:
    print(directory)

This method is particularly suitable for scenarios requiring complete directory tree structures. Note that the returned list includes the starting directory itself. If you need to exclude the starting directory, you can use slicing: all_subdirectories[1:].

Methods for Obtaining Immediate Subdirectories

For scenarios requiring only immediate subdirectories without recursive traversal, Python provides more efficient solutions.

Using os.walk for Immediate Subdirectories

Although os.walk is primarily designed for recursive traversal, it can also be used to obtain immediate subdirectories:

import os

# Get immediate subdirectories of current directory
immediate_subdirs = next(os.walk('.'))[1]
print("Immediate subdirectories:", immediate_subdirs)

This approach leverages the fact that the second element returned by os.walk is the list of subdirectories, using the next() function to get the result of the first iteration.

Combining os.listdir and os.path.isdir

This is the most traditional method, listing directory contents and filtering for directory items:

import os

current_dir = '.'
immediate_subdirs = [
    os.path.join(current_dir, item) 
    for item in os.listdir(current_dir) 
    if os.path.isdir(os.path.join(current_dir, item))
]
print("Immediate subdirectories:", immediate_subdirs)

This method offers maximum flexibility, allowing easy addition of extra filtering conditions.

Using os.scandir (Python 3.5+)

os.scandir is an efficient directory traversal method introduced in Python 3.5:

import os

current_dir = '.'
subdirectories = [f.path for f in os.scandir(current_dir) if f.is_dir()]
print("Subdirectories:", subdirectories)

If you need only directory names instead of full paths, use f.name instead of f.path.

Using glob.glob for Pattern Matching

The glob module provides pattern matching functionality based on wildcards:

from glob import glob

subdirectories = glob("./*/")
print("Subdirectories:", subdirectories)

Note that the trailing / is essential, ensuring that only directories are matched. This method is concise and particularly suitable for simple directory matching requirements.

Using the pathlib Module (Python 3.4+)

pathlib provides object-oriented path operations:

from pathlib import Path

current_dir = Path('.')
subdirectories = [f for f in current_dir.iterdir() if f.is_dir()]
print("Subdirectories:", subdirectories)

This method returns Path objects, offering rich path manipulation methods.

Efficient Methods for Recursively Obtaining All Subdirectories

While os.walk can recursively obtain all subdirectories, custom recursive functions may be more efficient for large directory trees:

import os

def get_all_subdirectories(directory):
    """Recursively get all subdirectories under specified directory"""
    subdirectories = []
    
    for entry in os.scandir(directory):
        if entry.is_dir():
            subdirectories.append(entry.path)
            # Recursively get subdirectories of subdirectories
            subdirectories.extend(get_all_subdirectories(entry.path))
    
    return subdirectories

# Usage example
all_subdirs = get_all_subdirectories('.')
print(f"Total found {len(all_subdirs)} subdirectories")

Performance Analysis and Comparison

Different methods show significant performance variations. The following performance data is based on actual testing (in a test environment containing 439 directories):

The performance data clearly shows that os.scandir has a distinct advantage when obtaining immediate subdirectories, while os.walk performs relatively poorly due to the need to construct the complete directory tree.

Application Scenarios and Selection Recommendations

Based on different requirement scenarios, the following selections are recommended:

  1. Only immediate subdirectories needed: Prefer os.scandir for best performance
  2. Recursive all subdirectories needed: Use os.walk or custom recursive functions
  3. Simple pattern matching: Use glob.glob
  4. Object-oriented path operations: Use pathlib
  5. Maximum compatibility: Use os.listdir + os.path.isdir

Error Handling and Edge Cases

In practical applications, various edge cases and error handling need to be considered:

import os

def safe_get_subdirectories(directory):
    """Safely get subdirectories with error handling"""
    try:
        if not os.path.exists(directory):
            raise FileNotFoundError(f"Directory {directory} does not exist")
        
        if not os.path.isdir(directory):
            raise NotADirectoryError(f"{directory} is not a directory")
        
        return [f.path for f in os.scandir(directory) if f.is_dir()]
    
    except PermissionError:
        print(f"No permission to access directory: {directory}")
        return []
    except Exception as e:
        print(f"Error occurred while getting subdirectories: {e}")
        return []

# Usage example
subdirs = safe_get_subdirectories('.')
print("Safe subdirectory retrieval:", subdirs)

Conclusion

Python offers rich methods for obtaining subdirectories under a directory, each with specific advantages and applicable scenarios. When choosing a method, performance requirements, functional needs, and code readability should be comprehensively considered. For most modern applications, os.scandir is the preferred choice due to its excellent performance, while the traditional os.listdir combination method offers the best compatibility. Understanding the differences and characteristics of these methods will help developers write more efficient and robust directory operation code.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.