Как перечислить только каталоги верхнего уровня в Python?

Я хочу иметь возможность отображать только каталоги внутри какой-либо папки. Это означает, что мне не нужны перечисленные имена файлов и не нужны дополнительные подпапки.

Посмотрим, поможет ли пример. В текущем каталоге у нас есть:

>>> os.listdir(os.getcwd())
['cx_Oracle-doc', 'DLLs', 'Doc', 'include', 'Lib', 'libs', 'LICENSE.txt', 'mod_p
ython-wininst.log', 'NEWS.txt', 'pymssql-wininst.log', 'python.exe', 'pythonw.ex
e', 'README.txt', 'Removemod_python.exe', 'Removepymssql.exe', 'Scripts', 'tcl',
 'Tools', 'w9xpopen.exe']

Однако мне не нужно перечислять имена файлов. Мне также не нужны подпапки, такие как \ Lib \ curses. По сути, то, что я хочу, работает со следующим:

>>> for root, dirnames, filenames in os.walk('.'):
...     print dirnames
...     break
...
['cx_Oracle-doc', 'DLLs', 'Doc', 'include', 'Lib', 'libs', 'Scripts', 'tcl', 'Tools']

Однако мне интересно, есть ли более простой способ достичь тех же результатов. У меня сложилось впечатление, что использование os.walk только для возврата на верхний уровень неэффективно / слишком много.

os.walk () использует функцию генератора и не будет неэффективной, если вы используете ее только для верхнего уровня.

Rahul Purohit 28.09.2020 11:56
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
142
1
162 728
19
Перейти к ответу Данный вопрос помечен как решенный

Ответы 19

directories=[d for d in os.listdir(os.getcwd()) if os.path.isdir(d)]

Это можно сократить до filter (os.path.isdir, os.listdir (os.getcwd ())

John Millikin 27.09.2008 00:20

Есть ли у кого-нибудь информация о том, быстрее ли фильтр или понимание списка? В противном случае это просто субъективный аргумент. Это, конечно, предполагает, что в cwd 10 миллионов каталогов, и производительность является проблемой.

Mark Roddy 27.09.2008 03:12

Вот так?

>>>> [path for path in os.listdir(os.getcwd()) if os.path.isdir(path)]

[x for x in os.listdir(somedir) if os.path.isdir(os.path.join(somedir, x))]
Ответ принят как подходящий

Отфильтруйте результат с помощью os.path.isdir () (и используйте os.path.join (), чтобы получить реальный путь):

>>> [ name for name in os.listdir(thedir) if os.path.isdir(os.path.join(thedir, name)) ]
['ctypes', 'distutils', 'encodings', 'lib-tk', 'config', 'idlelib', 'xml', 'bsddb', 'hotshot', 'logging', 'doc', 'test', 'compiler', 'curses', 'site-packages', 'email', 'sqlite3', 'lib-dynload', 'wsgiref', 'plat-linux2', 'plat-mac']

Это требует много обработки по сравнению с очень простой os.walk (). Next () [1]

Phyo Arkar Lwin 13.08.2012 23:47

Отфильтруйте список с помощью os.path.isdir для обнаружения каталогов.

filter(os.path.isdir, os.listdir(os.getcwd()))

Я думаю, что это, безусловно, лучшее сочетание удобочитаемости и краткости в любом из этих ответов.

vergenzt 29.08.2012 17:56

Это не сработало. Я предполагаю, что os.listdir возвращает имя файла / папки, переданное os.path.isdir, но последнему нужен полный путь.

Daniel Reis 04.12.2012 15:50

фильтр быстрее, чем os.walk timeit(os.walk(os.getcwd()).next()[1])1000 loops, best of 3: 734 µs per looptimeit(filter(os.path.isdir, os.listdir(os.getcwd())))1000 loops, best of 3: 477 µs per loop

B.Kocis 18.05.2016 17:19

Комментарий здесь заключается в том, что os.listdir не возвращает абсолютный путь, поэтому filter(os.path.isdir, [os.path.join(base, f) for f in os.listdir(base)]) решил это за меня.

Hunaphu 22.10.2020 14:41

Обратите внимание, что вместо os.listdir(os.getcwd()) предпочтительнее использовать os.listdir(os.path.curdir). На один вызов функции меньше, и он такой же переносимый.

Итак, чтобы завершить ответ, получить список каталогов в папке:

def listdirs(folder):
    return [d for d in os.listdir(folder) if os.path.isdir(os.path.join(folder, d))]

Если вы предпочитаете полные пути, используйте эту функцию:

def listdirs(folder):
    return [
        d for d in (os.path.join(folder, d1) for d1 in os.listdir(folder))
        if os.path.isdir(d)
    ]

os.walk

Используйте os.walk с функцией элемента next:

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

Для Python <= 2.5 используйте:

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

Как это работает

os.walk - это генератор, и при вызове next будет получен первый результат в виде трех кортежей (dirpath, dirnames, filenames). Таким образом, индекс [1] возвращает только dirnames из этого кортежа.

Еще немного описания: это генератор, он не будет ходить по другим каталогам, если вы ему не скажете. Итак .next () [1] в одной строке выполняет то же самое, что и все представления списка. Я бы, вероятно, сделал что-то вроде DIRNAMES=1, а затем next()[DIRNAMES], чтобы облегчить понимание для будущих разработчиков кода.

boatcoder 15.11.2012 19:49

+1 потрясающее решение. Чтобы указать каталог для просмотра, используйте: os.walk( os.path.join(mypath,'.')).next()[1]

Daniel Reis 04.12.2012 15:53

для python v3: next (os.walk ('.')) [1]

Andre Soares 21.12.2012 02:14

если вы собираетесь делать больше, чем обработка текста; т.е. обработка в фактических папках, тогда могут потребоваться полные пути: sorted( [os.path.join(os.getcwd(), item) for item in os.walk(os.curdir).next()[1]] )

DevPlayer 04.01.2013 03:35

почему точка? next(os.walk('.'))[1]

BERA 21.12.2020 20:43

. указывает текущий каталог. Это эквивалент os.getcwd().

Alex Coventry 22.12.2020 22:29

будучи здесь новичком, я пока не могу напрямую комментировать, но вот небольшое исправление, которое я хотел бы добавить в следующую часть ΩΤΖΙΟΥ ответ:

If you prefer full pathnames, then use this function:

def listdirs(folder):  
  return [
    d for d in (os.path.join(folder, d1) for d1 in os.listdir(folder))
    if os.path.isdir(d)
]

для тех, кто все еще использует python <2.4: внутренняя конструкция должна быть списком, а не кортежем, и поэтому должна читаться так:

def listdirs(folder):  
  return [
    d for d in [os.path.join(folder, d1) for d1 in os.listdir(folder)]
    if os.path.isdir(d)
  ]

в противном случае возникает синтаксическая ошибка.

Я знаю, что это было давно, но этот первый пример мне очень помог.

Inbar Rose 02.08.2012 13:24

Вы получаете синтаксическую ошибку, потому что ваша версия не поддерживает выражения генератора. Они были введены в Python 2.4, тогда как понимание списков было доступно с Python 2.0.

awatts 21.08.2013 14:18

Просто добавлю, что использование os.listdir () не "требуется много обработки по сравнению с очень простой os.walk (). next () [1]". Это потому, что os.walk () внутренне использует os.listdir (). Фактически, если вы протестируете их вместе:

>>>> import timeit
>>>> timeit.timeit("os.walk('.').next()[1]", "import os", number=10000)
1.1215229034423828
>>>> timeit.timeit("[ name for name in os.listdir('.') if os.path.isdir(os.path.join('.', name)) ]", "import os", number=10000)
1.0592019557952881

Фильтрация os.listdir () выполняется немного быстрее.

В Python 3.5 есть более быстрый способ получения содержимого каталога: python.org/dev/peps/pep-0471

foz 13.08.2015 19:03

pep-0471 - пакет scandir - доступен для Python 2.6 и более поздних версий в качестве устанавливаемого пакета на PyPI. Он предлагает замену os.walk и os.listdir, которая работает намного быстрее.

foz 03.02.2017 20:06

Для списка полных имен я предпочитаю эту версию другим решения здесь:

def listdirs(dir):
    return [os.path.join(os.path.join(dir, x)) for x in os.listdir(dir) 
        if os.path.isdir(os.path.join(dir, x))]

Более простой и элегантный способ - использовать это:

 import os
 dir_list = os.walk('.').next()[1]
 print dir_list

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

Кажется, это тоже работает (по крайней мере, на Linux):

import glob, os
glob.glob('*' + os.path.sep)

+1 для glob. Это может сэкономить вам много кода, особенно итераций, и очень похоже на использование терминала UNIX (ls).

Gerard 09.08.2016 12:12

Вместо glob.glob ('*' + os.path.sep) вы можете написать [dir вместо dir в glob.glob ("*"), если os.path.isdir (dir)]

Eamonn M.R. 10.12.2016 00:45

Более безопасный вариант, который не подведет, когда нет каталога.

def listdirs(folder):
    if os.path.exists(folder):
         return [d for d in os.listdir(folder) if os.path.isdir(os.path.join(folder, d))]
    else:
         return []

scanDir = "abc"
directories = [d for d in os.listdir(scanDir) if os.path.isdir(os.path.join(os.path.abspath(scanDir), d))]

-- This will exclude files and traverse through 1 level of sub folders in the root

def list_files(dir):
    List = []
    filterstr = ' '
    for root, dirs, files in os.walk(dir, topdown = True):
        #r.append(root)
        if (root == dir):
            pass
        elif filterstr in root:
            #filterstr = ' '
            pass
        else:
            filterstr = root
            #print(root)
            for name in files:
                print(root)
                print(dirs)
                List.append(os.path.join(root,name))
            #print(os.path.join(root,name),"\n")
                print(List,"\n")

    return List

Используя понимание списка,

[a for a in os.listdir() if os.path.isdir(a)]

Я думаю это самый простой способ

Python 3.4 представил модуль pathlib в стандартной библиотеке, которая обеспечивает объектно-ориентированный подход для обработки путей файловой системы:

from pathlib import Path

p = Path('./')
[f for f in p.iterdir() if f.is_dir()]

FWIW, подход os.walk почти в 10 раз быстрее, чем подходы к пониманию и фильтрации списков:

In [30]: %timeit [d for d in os.listdir(os.getcwd()) if os.path.isdir(d)]
1.23 ms ± 97.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [31]: %timeit list(filter(os.path.isdir, os.listdir(os.getcwd())))
1.13 ms ± 13.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [32]: %timeit next(os.walk(os.getcwd()))[1]
132 µs ± 9.34 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Вы также можете использовать os.scandir:

with os.scandir(os.getcwd()) as mydir:
    dirs = [i.name for i in mydir if i.is_dir()]

Если вам нужен полный путь, вы можете использовать i.path.

Using scandir() instead of listdir() can significantly increase the performance of code that also needs file type or file attribute information, because os.DirEntry objects expose this information if the operating system provides it when scanning a directory.

Другие вопросы по теме