Як перелічити лише каталоги верхнього рівня в Python?


132

Я хочу мати змогу перераховувати лише каталоги всередині якоїсь папки. Це означає, що я не хочу перелічувати імена файлів, а також не хочу додаткових підпапок.

Подивимось, чи допомагає приклад. У поточному каталозі ми маємо:

>>> 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 лише для повернення верхнього рівня неефективно / занадто багато.

Відповіді:


125

Фільтруйте результат за допомогою 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']

17
Це займе багато обробки проти дуже простого os.walk (). Наступний () [1]
П'є Аркар Лвін

203

os.walk

Використовувати os.walkз nextфункцією елемента:

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

Для Python <= 2,5 використовуйте:

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

Як це працює

os.walkє генератором і виклик nextотримає перший результат у вигляді 3-кортежу (dirpath, dirnames, filename). Таким чином, [1]індекс повертає лише dirnamesз цього кортежу.


14
Ще трохи опису з цього приводу полягає в тому, що це генератор, він не буде ходити по інших брудах, якщо ви цього не скажете. Отже .next () [1] робить в одному рядку те, що роблять усі розуміння списку. Я, мабуть, зробив щось на кшталт DIRNAMES=1того, next()[DIRNAMES]щоб потім було легше зрозуміти майбутніми кодами.
boatcoder

3
+1 дивовижне рішення. Щоб вказати каталог для перегляду, використовуйте:os.walk( os.path.join(mypath,'.')).next()[1]
Даніель Рейс

42
для python v3: next (os.walk ('.')) [1]
Андре Соарес

якщо ви збираєтеся робити більше, ніж обробка тексту; тобто обробка у sorted( [os.path.join(os.getcwd(), item) for item in os.walk(os.curdir).next()[1]] )
власних

52

Фільтруйте список, використовуючи os.path.isdir для виявлення каталогів.

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

5
Я думаю, що це далеко не найкраще поєднання читабельності та лаконічності в будь-якій з цих відповідей.
vergenzt

20
Це не спрацювало. Я здогадуюсь, що os.listdirповертає ім’я файлу / папки, переданий на os.path.isdir, але останнім потрібен повний шлях.
Даніель Рейс

3
фільтр швидший, ніж os.walk timeit(os.walk(os.getcwd()).next()[1]) 1000 loops, best of 3: 734 µs per loop timeit(filter(os.path.isdir, os.listdir(os.getcwd()))) 1000 loops, best of 3: 477 µs per loop
B.Kocis

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

4
Це можна скоротити до фільтра (os.path.isdir, os.listdir (os.getcwd ())
Джон Міллікін

3
Хтось має інформацію про те, чи швидше розуміння фільтра чи списку? Інакше це просто суб'єктивний аргумент. Звичайно, передбачається, що в диспетчері є 10 мільйонів каталогів, а продуктивність - це проблема.
Марк Родді

12

Зауважте, що замість цього робити 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)
    ]

9

Це, здається, теж працює (принаймні, на Linux):

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

1
+1 для glob. Це може заощадити багато коду, особливо ітерацій, і дуже схоже на використання терміналу UNIX ( ls)
Джерард

5
Замість того, щоб glob.glob ('*' + os.path.sep) ви можете написати [dir for dir в glob.glob ("*"), якщо os.path.isdir (dir)]
Eamonn MR

8

Просто додамо, що використання 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 () відбувається дуже дещо швидше.


2
Перехід на Python 3.5 - це більш швидкий спосіб отримання вмісту каталогів: python.org/dev/peps/pep-0471
foz

1
pep-0471 - scandirпакет - з радістю доступний для Python 2.6 і далі, як інстальований пакет на PyPI. Він пропонує заміни, os.walkі os.listdirце набагато швидше.
foz

6

Дуже простішим і елегантним способом є використання цього:

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

Запустіть цей скрипт у тій самій папці, для якої ви хочете імена папок. Він дасть вам саме те саме ім'я папок (що теж без повного шляху папок).


6

Використовуючи розуміння списку,

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

Я думаю, що це найпростіший спосіб


2

будучи новачком тут, я ще не можу прямо коментувати, але ось невелике виправлення, яке я хотів би додати до наступної частини відповіді ΤΖΩΤΖΙΟΥ :

Якщо ви віддаєте перевагу повних імен, використовуйте цю функцію:

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)
  ]

інакше виникає синтаксична помилка.


я знаю, що минуло деякий час, але цей перший приклад мені дуже допоміг.
Інбар Роза

1
Ви отримуєте синтаксичну помилку, оскільки ваша версія не підтримує вирази генератора. Вони були представлені в Python 2.4, тоді як розуміння списків були доступні з Python 2.0.
awatts

1
[x for x in os.listdir(somedir) if os.path.isdir(os.path.join(somedir, x))]

1

Для переліку повних імен шляхів я віддаю перевагу цій версії перед іншими рішеннями тут:

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))]

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

0

Більш безпечний варіант, який не виходить з ладу, коли немає каталогу.

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 []


0

Python 3.4 вводиться в pathlibмодулі в стандартну бібліотеку, яка забезпечує об'єктно - орієнтований підхід для обробки файлової системи шляхів:

from pathlib import Path

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

-1
-- 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.