'List directories with a specified depth in Python
I'm want a function to return a list with directories with a specified path and a fixed depth and soon realized there a few alternatives. I'm using os.walk quite a lot but the code started to look ugly when counting the depth etc.
What is really the most "neat" implementation?
Solution 1:[1]
This is not exactly neat, but under UNIX-like OS, you could also rely on a system tool like "find", and just execute it as an external program, for example:
from subprocess import call
call(["find", "-maxdepth", "2", "-type", "d"])
You can then redirect the output to some string variable for further handling.
Solution 2:[2]
A simple, recursive solution using os.scandir:
def _walk(path, depth):
"""Recursively list files and directories up to a certain depth"""
depth -= 1
with os.scandir(path) as p:
for entry in p:
yield entry.path
if entry.is_dir() and depth > 0:
yield from _walk(entry.path, depth)
Solution 3:[3]
I really like phihag's answer. I adapted it to suit my needs.
import fnmatch,glob
def fileNamesRetrieve( top, maxDepth, fnMask ):
someFiles = []
for d in range( 1, maxDepth+1 ):
maxGlob = "/".join( "*" * d )
topGlob = os.path.join( top, maxGlob )
allFiles = glob.glob( topGlob )
someFiles.extend( [ f for f in allFiles if fnmatch.fnmatch( os.path.basename( f ), fnMask ) ] )
return someFiles
I guess I could also make it a generator with something like this:
def fileNamesRetrieve( top, maxDepth, fnMask ):
for d in range( 1, maxDepth+1 ):
maxGlob = "/".join( "*" * d )
topGlob = os.path.join( top, maxGlob )
allFiles = glob.glob( topGlob )
if fnmatch.fnmatch( os.path.basename( f ), fnMask ):
yield f
Critique welcome.
Solution 4:[4]
Here's a simple function to do this
import os
from glob import glob
from pathlib import Path
def find_sub_dirs(path, depth=2):
path = Path(path)
assert path.exists(), f'Path: {path} does not exist'
depth_search = '*/' * depth
search_pattern = os.path.join(path, depth_search)
return list(glob(f'{search_pattern}'))
Solution 5:[5]
Note that @phihag's great suggestion also works with pathlib.Path.glob:
from pathlib import Path
from typing import List
def get_subitems(folder: Path, level: int) -> List[Path]:
if level == 0:
return [item]
pattern = "/".join(["*"] * level)
return sorted(item for item in item.glob(pattern))
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Marek Waligórski |
| Solution 2 | Gregor Sturm |
| Solution 3 | John Schmitt |
| Solution 4 | Deep Patel |
| Solution 5 | Chris_128 |
