Вопрос-Ответ

Getting a list of all subdirectories in the current directory

Получение списка всех подкаталогов в текущем каталоге

Есть ли способ вернуть список всех подкаталогов в текущем каталоге в Python?

Я знаю, что вы можете сделать это с файлами, но вместо этого мне нужно получить список каталогов.

Переведено автоматически
Ответ 1

Вы имеете в виду непосредственные подкаталоги или каждый каталог прямо по дереву?

В любом случае, вы могли бы использовать os.walk для этого:

os.walk(directory)

выдаст кортеж для каждого подкаталога. Первая запись в 3-м кортеже - это имя каталога, поэтому

[x[0] for x in os.walk(directory)]

должно предоставить вам все подкаталоги рекурсивно.

Обратите внимание, что вторая запись в кортеже - это список дочерних каталогов записи на первой позиции, поэтому вы могли бы использовать это вместо, но вряд ли это сильно сэкономит вам.

Однако вы могли бы использовать его только для предоставления вам непосредственных дочерних каталогов:

next(os.walk('.'))[1]

Или ознакомьтесь с другими уже опубликованными решениями, используя os.listdir и os.path.isdir, в том числе в разделе "Как получить все непосредственные подкаталоги в Python".

Ответ 2

Вы могли бы просто использовать glob.glob

from glob import glob
glob("/path/to/directory/*/", recursive = True)

Не забудьте о конце / после *.

Ответ 3

Намного приятнее, чем вышеописанное, потому что вам не нужно несколько os.path.join() и вы получите полный путь напрямую (при желании), вы можете сделать это в Python 3.5 и выше.

subfolders = [ f.path for f in os.scandir(folder) if f.is_dir() ]

Это даст полный путь к подкаталогу.
Если вам нужно только название подкаталога, используйте f.name вместо f.path

https://docs.python.org/3/library/os.html#os.scandir


Немного О том, что: в случае, если вам нужны все вложенные папки рекурсивно и / или все файлы рекурсивно, взгляните на эту функцию, которая быстрее, чем os.walk & glob и вернет список всех вложенных папок, а также всех файлов внутри этих (вложенных)папок: https://pythonly.ru/a/59803793/2441026

На случай, если вам нужны только все вложенные папки рекурсивно:

def fast_scandir(dirname):
subfolders= [f.path for f in os.scandir(dirname) if f.is_dir()]
for dirname in list(subfolders):
subfolders.extend(fast_scandir(dirname))
return subfolders

Возвращает список всех вложенных папок с их полными путями. Это снова быстрее, чем os.walk и намного быстрее, чем glob.


Анализ всех функций

tl; dr:
- Если вы хотите получить все непосредственные подкаталоги для папки , используйте os.scandir.
- Если вы хотите получить все подкаталоги, даже вложенные, используйте os.walk или - немного быстрее - fast_scandir функцию выше.
- Никогда не используйте os.walk только для подкаталогов верхнего уровня, так как это может быть в сотни (!) раз медленнее, чем os.scandir.


  • Если вы запустите приведенный ниже код, обязательно запустите его один раз, чтобы ваша операционная система получила доступ к папке, отмените результаты и запустите тест, в противном случае результаты будут испорчены.

  • Возможно, вы захотите перепутать вызовы функций, но я протестировал это, и это действительно не имело значения.

  • Во всех примерах будет указан полный путь к папке. Пример pathlib в виде объекта Path (Windows).

  • Первым элементом os.walk будет базовая папка. Таким образом, вы получите не только подкаталоги. Вы можете использовать fu.pop(0), чтобы удалить его.

  • Ни в одном из результатов не будет использоваться естественная сортировка. Это означает, что результаты будут отсортированы следующим образом: 1, 10, 2. Чтобы получить естественную сортировку (1, 2, 10), пожалуйста, взгляните на https://pythonly.ru/a/48030307/2441026


Результаты:

os.scandir      took   1 ms. Found dirs: 439
os.walk took 463 ms. Found dirs: 441 -> it found the nested one + base folder.
glob.glob took 20 ms. Found dirs: 439
pathlib.iterdir took 18 ms. Found dirs: 439
os.listdir took 18 ms. Found dirs: 439

Протестировано с W7x64, Python 3.8.1.


# -*- coding: utf-8 -*-
# Python 3


import time
import os
from glob import glob
from pathlib import Path


directory = r"<insert_folder>"
RUNS = 1


def run_os_walk():
a = time.time_ns()
for i in range(RUNS):
fu = [x[0] for x in os.walk(directory)]
print(f"os.walk\t\t\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found dirs: {len(fu)}")


def run_glob():
a = time.time_ns()
for i in range(RUNS):
fu = glob(directory + "/*/")
print(f"glob.glob\t\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found dirs: {len(fu)}")


def run_pathlib_iterdir():
a = time.time_ns()
for i in range(RUNS):
dirname = Path(directory)
fu = [f for f in dirname.iterdir() if f.is_dir()]
print(f"pathlib.iterdir\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found dirs: {len(fu)}")


def run_os_listdir():
a = time.time_ns()
for i in range(RUNS):
dirname = Path(directory)
fu = [os.path.join(directory, o) for o in os.listdir(directory) if os.path.isdir(os.path.join(directory, o))]
print(f"os.listdir\t\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms. Found dirs: {len(fu)}")


def run_os_scandir():
a = time.time_ns()
for i in range(RUNS):
fu = [f.path for f in os.scandir(directory) if f.is_dir()]
print(f"os.scandir\t\ttook {(time.time_ns() - a) / 1000 / 1000 / RUNS:.0f} ms.\tFound dirs: {len(fu)}")


if __name__ == '__main__':
run_os_scandir()
run_os_walk()
run_glob()
run_pathlib_iterdir()
run_os_listdir()
Ответ 4
import os

d = '.'
[os.path.join(d, o) for o in os.listdir(d)
if os.path.isdir(os.path.join(d,o))]
python